boston-key-party-ctf-part-writeup

##0x00

周末的 boston key party ctf 比赛,第二天注册了帐号玩了一下,也仅仅能够做一些简单题。
题目类型有二进制,逆向,加密,”School bus”
所谓的学校汽车应该就是指学生能做的题吧,我也只能做这些了。

“School bus” 分类下的题目有这些:

  • Park Street : 10 (pass)
  • BU Central : 10
  • Brigham Circle : 25 (pass)
  • Longwood Medical : 25 (pass)
  • Museum of Fine Arts : 25 (pass)
  • Northeastern Univ. : 25 (pass)
  • Symphony : 25 (pass)
  • Prudential : 25 (pass)
  • Heath Street : 100
  • Riverside : 200

接下来一个一个分析吧。

##0x01

BU Central:the flag is party : 10

题目中直接提示the flag is party
所以 flag 就是 party

##0x02

Longwood Medical:Because we dont trust mysqli_real_escape_string, we wrote our own military-grade sanitization method. : 25

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<html>
<head>
<title>level5</title>
<link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php

require 'flag.php';

if (isset ($_GET['name']) and isset ($_GET['password'])) {
$name = $_GET['name'];
$password = $_GET['password'];

if (ctype_alnum ($name) and ctype_alnum ($password)) {
$request = 'SELECT login FROM user where login = ' . $name . ' AND password = ' . $password . ';';
$db = new SQLite3 (sha1($flag).'.db', SQLITE3_OPEN_READONLY); // Ghetto anti-database-download
$result = $db->querySingle ($request);
$db->close ();

if ($result === FALSE)
echo '<p class="alert">"Invalid login or password</p>';
else
die('Flag: ' . $flag);
} else
echo '<p class="alert">Invalid chars detected</p>';
}
?>

<section class="login">
<div class="title">
<a href="./index.txt">Level 5</a>
</div>

<form method="get">
<input type="text" required name="name" placeholder="Name"/><br/>
<input type="text" required name="password" placeholder="Password" /><br/>
<input type="submit"/>
</form>
</section>
</body>
</html>

这道题不知道是什么类型的。要求输入两个参数,要求是数字,然后有查询数据库什么的。
直接尝试提交 12345,12345 就得到 flag,莫名奇妙pass~
Flag: Did_you_know_that_in_french_a_chiken_makes_the_sound_quotquotquotquot?

##0x03

Museum of Fine Arts: Because cryptography is hard, we only implemented a hand-made PRNG. What could possibly go wrong? : 25

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<html>
<head>
<title>level4</title>
<link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
session_start();

require 'flag.php';

if (isset ($_GET['password'])) {
if ($_GET['password'] == $_SESSION['password'])
die ('Flag: '.$flag);
else
print '<p class="alert">Wrong guess.</p>';
}

// Unpredictable seed
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>


<section class="login">
<div class="title">
<a href="./index.txt">Level 4</a>
</div>

<ul class="list">
<?php
for ($i=0; $i<3; $i++)
print '<li>' . mt_rand (0, 0xffffff) . '</li>';
$_SESSION['password'] = mt_rand (0, 0xffffff);
?>

</ul>

<form method="get">
<input type="text" required name="password" placeholder="Next number" /><br/>
<input type="submit"/>
</form>
</section>
</body>
</html>

本题考察PHP中伪随机数的生成。我们都知道,我们常用的随机数其实都是伪随机,指定种子(seed),得到的随机数是相同的。
源码中seed的范围不大,我们可以写个脚本遍历该范围内的种子,其随机序列中的前四个。
然后即可得知本次使用的种子,也就得到了第四次随机数。
提交得到 Flag: It_s33ms_that_PRNG_are_hard_too_after_all

程序如下:

1
2
3
4
5
6
7
8
9
10
<?php
for ($i=1; $i<=20000; $i++){
mt_srand($i);
echo $i, ": ";
for ($j=0; $j<4; $j++){
echo mt_rand(0, 0xffffff),",";
}
echo "\n";
}
?>

##0x04

Northeastern Univ.:Of course, a timing attack might be the answer, but Im quite sure that you can do better than that. : 25

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<html>
<head>
<title>level3</title>
<link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['password'])) {
if (strcmp($_GET['password'], $flag) == 0)
die('Flag: '.$flag);
else
print '<p class="alert">Invalid password.</p>';
}
?>


<section class="login">
<div class="title">
<a href="./index.txt">Level 3</a>
</div>

<form method="get">
<input type="text" required name="password" placeholder="Password" /><br/>
<input type="submit"/>
</form>
</section>
</body>
</html>

需要输入一个密码,程序得到这个密码用 strcmp 和 flag 比较,如果 strcmp 返回值为0, 则输出 flag
这里需要利用PHP语言的弱类型这个特性(漏洞)
若 strcmp 中的参数有一个为数组,则返回0

所以我们构造?password[]=a,提交即可得到答案
Flag: Still_better_than_the_d0uble_equals

##0x05

Symphony: A less than four characters number, bigger than 999?Maybe the bug is elsewhere. : 25

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<html>
<head>
<title>level2</title>
<link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['password'])) {
if (is_numeric($_GET['password'])){
if (strlen($_GET['password']) < 4){
if ($_GET['password'] > 999)
die('Flag: '.$flag);
else
print '<p class="alert">Too little</p>';
} else
print '<p class="alert">Too long</p>';
} else
print '<p class="alert">Password is not numeric</p>';
}
?>


<section class="login">
<div class="title">
<a href="./index.txt">Level 2</a>
</div>

<form method="get">
<input type="text" required name="password" placeholder="Password" /><br/>
<input type="submit"/>
</form>
</section>
</body>
</html>

提交一个值 ——> 判断是不是数字 ——> 判断是不是小于四位数 ——> 判断是不是大于999
如果以上条件均符合,那么就可以得到 flag 了。

也就是说,我们要提交一个值,既要是数字,不能大于四位数,还得大于999
那么常规的数字是不行的。但是!PHP是如何判断你输入的是不是数字呢?

我们来看一下官方文档中对 is_numeric 函数的说明。

Finds whether the given variable is numeric. Numeric strings consist of optional sign, 
any number of digits, optional decimal part and optional exponential part. Thus 
+0123.45e6 is a valid numeric value. Hexadecimal (e.g. 0xf4c3b00c), Binary (e.g. 0b10100111001), 
Octal (e.g. 0777) notation is allowed too but only without sign, decimal and exponential part. 

Returns TRUE if var is a number or a numeric string, FALSE otherwise. 

所以我们输入9e9(远远大于999)提交即可得到flag

##0x06

Prudential: I dont think that sha1 is broken. Prove me wrong. : 25

代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<html>
<head>
<title>level1</title>
<link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['name']) and isset($_GET['password'])) {
if ($_GET['name'] == $_GET['password'])
print 'Your password can not be your name.';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
print '<p class="alert">Invalid password.</p>';
}
?>


<section class="login">
<div class="title">
<a href="./index.txt">Level 1</a>
</div>

<form method="get">
<input type="text" required name="name" placeholder="Name"/><br/>
<input type="text" required name="password" placeholder="Password" /><br/>
<input type="submit"/>
</form>
</section>
</body>
</html>

原理如上,构造?name[]=a&password[]=b,提交
Flag: I_think_that_I_just_broke_sha1
(本地测试sha1()函数中参数不能为数组,不明觉力。另外这道题如果去考虑sha1碰撞的话,那就跑偏了)

#0x07
小结一下吧,做出来的题目基本上是代码审计,找到了些小技巧,抖了抖机灵。
还有三个没做出来。更别说加密,逆向,二进制这些了,我只是看了看题。

今天下午老师讲了些东西,我感觉是时候去认真的学好一个东西了,在哪一方面研究到一定的程度。
这个学期希望我能作出选择。

晚安

一些参考: