Web做题记录—ctfshow阿呆的故事第一季

程序员从入门到删库跑路


Web1

“代码很安全,没有漏洞”

打开容器后代码如下:

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
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

阅读代码我们可以看出,代码确实做的天衣无缝,代码大意是不让我们输入一个大于999的id去进行数据库查询,但是我们想要的flag却在第1000行。在这时,我们灵光一闪发现可以使用or逻辑判断的特殊性,语句一or语句二当语句一为真的时候不会进行语句二的真假判断,当语句一为假的时候才会进行下去所以我们可以通过这个性质构造这个安全的代码的漏洞:?id=1 or id=1000没有成功取得flag,因为id=1可以查询到内容,所以我们直接尝试用id=999继续构造,最终成功读取flag

ctfshow{c3485458-6282-476a-bbc4-5cf9831ea6d5}


Web2

“管理员赶紧修补了漏洞,这下应该没问题了吧”

同样打开容器,阅读代码

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>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/or|\+/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}
?>
</body>
<!-- flag in id = 1000 -->
</html>

由此可见我们之前用过的or语句被正则过滤掉了,但是问题不大,我们可以使用||代替or绕过
使用语句id=999 || id = 1000 拿到flag ctfshow{22be0842-65d9-4cd8-b2f0-90fa9db82652}


Web3

“管理员被狠狠的教育了,所以决定好好修复一番。这次没问题了”
老规矩先查看代码

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
44
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/or|\-|\\|\*|\<|\>|\!|x|hex|\+/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

这阿呆被批评也没用啊,依旧没有ban掉双管道符,继续上一题的处理方法就可以了
ctfshow{2ff4e4bb-8ea4-433f-b8e7-d00049a022a7}


Web4

“管理员阿呆又失败了,这次一定要堵住漏洞”

查看代码

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
44
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/or|\-|\\\|\/|\\*|\<|\>|\!|x|hex|\(|\)|\+|select/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

······怎么说呢,貌似还能用双管道符绕过 阿呆这修bug不过脑子啊
ctfshow{5416a936-25ec-4ddc-a7d0-32b456fe40b1}


Web5

“阿呆被老板狂骂一通,决定改掉自己大意的毛病,痛下杀手,修补漏洞”

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
44
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\!|x|hex|\(|\)|\+|select/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

这次终于双管道符的漏洞修复了,仔细看看这次还有什么没有被过滤的,这时候就要依靠一个叫做字节构造的知识点进行url的构造了
字节构造:
那么我们了解了这个知识点以后,可以使用如下的方法构造id=1000:?id=~~1000
成功获取flag ctfshow{5a0309f0-ba81-4039-8009-b0e574abb08d}


Web6

“阿呆一口老血差点噎死自己,决定杠上了”

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
44
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|x|hex|\(|\)|\+|select/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

并没有过滤~,所以使用与上一题相同的url即可过关


Web7

“阿呆得到最高指示,如果还出问题,就卷铺盖滚蛋,阿呆心在流血”

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
44
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|\~|x|hex|\(|\)|\+|select/i",$id)){
die("id error");
}
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error");
}else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值$row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>";
}
}
# 关闭数据库连接
$conn->close();
}

}else{
highlight_file(__FILE__);
}

?>
</body>
<!-- flag in id = 1000 -->
</html>

可以从表达式中看到,这次修复的很多,符号基本被ban的没剩下几个了,在这个时候,由于php所具有的二进制弱类型,如果转化二进制的话,由于开头的0b会被解析为0,可以直接绕过id必须小于999的判断,但是在进行sql语句查询的过程中又会被转化为正常的二进制进行执行,所以我们可以考虑一下使用二进制的方法进行绕过/?id=0b1111101000,成功获取得到flagctfshow{1f89ecdb-bc2a-48bf-a13c-5876dfa989cf}


Web8

“阿呆熟悉的一顿操作,去了埃塞尔比亚”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html>
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件,key flag 也在里面定义
include("config.php");
# 判断get提交的参数id是否存在
if(isset($_GET['flag'])){
if(isset($_GET['flag'])){
$f = $_GET['flag'];
if($key===$f){
echo $flag;
}
}
}else{
highlight_file(__FILE__);
}

?>
</body>
</html>

咦?代码突然怎么这么少,听说这题是个梗题,那么自然而然想到了那句话,程序和程序员能跑一个就行,现在埃塞俄比亚那肯定是程序员跑了,那自然而然跑路前要先删库hhhhh,使用经典代码rm -rf /*成功获得flag ctfshow{26e79749-373d-4ca4-848c-a8ca5320f115}


总结与知识点补充

阿呆的八个题目是正则绕过与sql查询的联合知识点,前几个题目依次运用了‘or’、‘||’、‘~’、‘二进制’等题目,最后一个梗题使用到了经典的删库语句,颇有新意,在这里需要补充一些正则中的一些绕过技巧
1.